Linux terminal tool dosent run one of the getopt commands - c

So I have a simple terminal tool here that makes use of getopt but when I run it everything runs smoothly except "cast -s" it returns "cast: invalid option -- 's'" but it fails silently without any error messages. Ive tried it on different hardware, operating systems and more but it dosent seem to work just right
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#define DATA_SIZE 1000
void print_help(void)
{
printf("Help\n");
printf("> cast -d (deletes file)\n");
printf("> cast -r (renames file)\n");
printf("> cast -c (create new file)\n");
printf("> cast -s (scans for file in directory)\n");
printf("________________________________________\n");
printf("Find an error or a bug? please submit it in the issues section on github\n");
}
int main(int argc, char **argv)
{
int option_val = 0;
int opt_delete = 0;
int opt_help = 0;
int opt_rename = 0;
int opt_create = 0;
int opt_scan = 0;
while ((option_val = getopt(argc, argv, "dhrc")) != -1) {
switch (option_val) {
case 'd':
char filename[65]; //Hope your filename isnt bigger than this
printf("Filename or path to file: ");
scanf("%s", filename); // checks to see if your filename isnt bigger than specified
if (remove(filename) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s, deleted.\n", filename);
opt_delete = 1;
break;
case 's':
{
DIR *dp;
struct dirent *dirp;
if (argc != 2) {
fprintf(stderr, "usage: s directory_name\n");
return 1;
}
if ((dp = opendir(argv[1])) == NULL) {
perror("cant copen");
return 2;
}
while((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
return 0;
}
opt_scan = 1;
break;
case 'r':
char file[65], new[65];
printf("File: ");
scanf("%s", file);
printf("New name: ");
scanf("%s", new);
if (rename(file, new) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s --> %s", file, new);
opt_rename = 1;
break;
case 'c':
FILE *f = fopen("Castdocument.txt", "w+");
fprintf(f, "Finished with maybe no errors? Rename this file to whatever you would like and change the filename extension with ""cast -r""");
printf("File created! (Check your home directory for ""Castdocument.txt"" file and modify that to fit your needs)");
fclose(f);
opt_create = 1;
break;
case 'h':
opt_help = 1;
break;
default: /* '?' */
//print_help();
}
}
if (opt_delete) {
printf("\n");
} if (opt_rename) {
printf("\n");
} if (opt_help) {
print_help();
} if (opt_create) {
printf("\n");
}
}
Ive attempted to run this on a different system to no avail

Related

's' case with getopt dosent print out the active files

This certain getopt case is supposed to be used as an ls (the unix/linux command) alternative that returns the active files but once compiled and ran nothing is returned in the terminal.
Here is the full code:
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#define DATA_SIZE 1000
void print_help(void)
{
printf("Help\n");
printf("> cast -d (deletes file)\n");
printf("> cast -r (renames file)\n");
printf("> cast -c (create new file)\n");
printf("> cast -s (searches contents of file)\n");
printf("________________________________________\n");
printf("Find an error or a bug? please submit it in the issues section on github\n");
}
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
int main(int argc, char **argv)
{
int option_val = 0;
int opt_delete = 0;
int opt_help = 0;
int opt_rename = 0;
int opt_create = 0;
int opt_search = 0;
while ((option_val = getopt(argc, argv, "dhrcs")) != -1) {
switch (option_val) {
case 'd': {
char filename[65]; //Hope your filename isnt bigger than this
printf("Filename or path to file: ");
scanf("%s", filename); // checks to see if your filename isnt bigger than specified
if (remove(filename) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s, deleted.\n", filename);
opt_delete = 1;
break;
case 'r': {
char file[65], new[65];
printf("File: ");
scanf("%s", file);
printf("New name: ");
scanf("%s", new);
if (rename(file, new) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s --> %s", file, new);
opt_rename = 1;
break;
case 'c': {
FILE *f = fopen("Castdocument.txt", "w+");
fprintf(f, "Finished with maybe no errors? Rename this file to whatever you would like and change the filename extension with ""cast -r""");
printf("File created! (Check your home directory for ""Castdocument.txt"" file and modify that to fit your needs)");
fclose(f);
opt_create = 1;
case 'h': {
print_help();
opt_help = 1;
break;
default:; /* '?' */
//print_help();
}
if (opt_delete) {
printf("\n");
} if (opt_rename) {
printf("\n");
} if (opt_help) {
print_help();
} if (opt_search) {
printf("\n");
} if (opt_create) {
printf("\n");
}
}
}
}
}
}
}
and here is the 's' case:
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
I attempted to move the case out of the switch statement but to no avail.

How to create hard/soft links in C?

I need to create a hard link to an existing file or directory.
I also need to create a soft/symbolic link to an existing file or directory. This is part of a larger program which is shown below. Commands are executed by typing "-f pathname linkname" and each break argument is a different command. I believe the functions -f, -d and -h have been created correctly so far. However I am having trouble creating these links.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
//Handles filename, absolute pathname
//Need relative pathname for -f
int main(int argc, char **argv)
{
char command[200], flag[20], pathname[100], linkname[100];
struct stat st = {0};
char cmd[200];
char *token; //Pointer
int counter = 1; //Counter variable
FILE *fp;
char mode2[] = "0750"; //To set the permission of a file/path
long j;
char mode[] = "0640"; //To set the permission of a file/path
long i;
printf("Enter command: ");
fgets(cmd, 420, stdin);
//User input is tokenized to determine the proper commands are entered and executed
token = strtok(cmd, " "); //Input is tokenized by white spaces.
if(token == NULL)
{
printf("Error with command input.\n");
exit(EXIT_FAILURE);
}
strcpy(command, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(flag, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(pathname, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(linkname, token);
//Switch statement to determine which command the user is choosing and execute that command.
switch(flag[1]) {
//The f case will create a file who's name is chosen by the user.
case 'f':
fp=fopen(pathname,"w");
fclose(fp);
char mode[] = "0640"; //Sets the permission of file to 0640.
i = strtol(mode, 0, 8);
if (chmod(pathname, i) < 0)
{
fprintf(stderr, "%s: error in chmod(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The d case will create a new directory chosen by the user.
case 'd':
if (stat(pathname, &st) == -1) {
mkdir(pathname, 0750); //Directory is given permission 0750.
}
j = strtol(mode, 0, 8);
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error in chmod(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The h case will create a hardlink to an existing file.
case 'h':
char *pathname; //Existing file
char *linkname; //Name of desired hardlink
int hlink; //Stores path
hlink = link(pathname, linkname); //Links linkname to pathname
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error linking(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The s case will create a symbol link to an existing file.
case 's':
char *pathname;
char *linkname;
int slink;
slink = symlink(pathname, linkname); //Using the symlink function to create a symbolic link of pathname
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error linking(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
}
}
POSIX
http://pubs.opengroup.org/onlinepubs/009695399/functions/link.html
http://pubs.opengroup.org/onlinepubs/009695399/functions/symlink.html
#include <unistd.h>
char *path1 = "/home/cnd/mod1";
char *path2 = "/modules/pass1";
int status;
...
status = link (path1, path2);
Windows
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createhardlinka
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinka
BOOL fCreatedLink = CreateHardLink( pszNewLinkName,
pszExistingFileName,
NULL ); // reserved, must be NULL
if ( fCreatedLink == FALSE )
{
;// handle error condition
}

A C program that copies all the content a directory including files and folders

The last Code I just posted now works. That is, it is able to copy all files from one directory to another. But now, I wanted to update it in such a way that it copies also directories including it contents be it files or folders.
Here is what I did so far, but this has been unable to accomplish my dream.
I really don't know what is wrong with the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define Max 8192
int copy_files(char *src, char *dest);
int copy_dir(char *srcpath, char *destpath);
int copy_dir(char *srcpath, char *destpath)
{
DIR *sdp = NULL;
DIR *ddp = NULL;
struct dirent *entry;
struct stat sb;
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
strcat(srcpath, "/");
strcat(destpath, "/");
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
if( (sdp = opendir(srcpath)) == NULL )
{
printf ("%s is not an existing directory\n", srcpath);
return 0;
}
else
{
while( (entry = readdir(sdp)) )
{
stat(entry->d_name, &sb);
// printf("Cannot open directory\n");
// exit(EXIT_FAILURE);
switch (sb.st_mode & S_IFMT)
{
case S_IFREG:
{
strcat(tempdest, entry->d_name);
strcat(tempsrc, entry->d_name);
copy_files(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
case S_IFDIR:
{
strcat(tempsrc, entry->d_name);
strcat(tempdest, entry->d_name);
mkdir(tempdest, 0777);
ddp = opendir(tempdest);
copy_dir(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
}
}
closedir(sdp);
closedir(ddp);
return 1;
}
}
int copy_files(char *src, char *dest)
{
int sfd, dfd, ret_in, ret_out;
char buff[Max];
if ( (sfd = open(src, O_RDONLY)) == -1 )
{
printf("Error while reading %s\n", src);
perror(src);
exit(1);
}
if ( (dfd = creat(dest, 0644)) == -1 )
{
printf("Error while creating %s\n", dest);
perror(dest);
exit(1);
}
while( (ret_in = read(sfd, &buff, Max)) > 0 )
{
ret_out = write (dfd, &buff, ret_in);
if (ret_out != ret_in)
{
printf("write error to %s", dest);
perror(dest);
exit(1);
}
if (ret_in == -1)
{
printf("read error from %s", src);
perror(src);
exit(1);
}
}
close(sfd);
close(dfd);
return 1;
}
int main(int argc, char *argv[])
{
int i;
if (argc != 3)
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
char *srcp = argv[1];
char *destp = argv[2];
if (srcp[0] == '/' && destp[0] == '/')
{
for (i = 1; i <= strlen(destp); i++)
destp[(i-1)] = destp[i];
for (i = 1; i <= strlen(srcp); i++)
srcp[(i-1)] = srcp[i];
copy_dir(srcp, destp);
}
else if (srcp[0] != '/' && destp[0] == '/') //./ass1 test /t2
{
for (i = 1; i <= strlen(destp); i++)
destp[i-1] = destp[i];
strcat(destp, "/");
strcat(destp, srcp);
copy_files(srcp, destp);
}
else
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
}
You are indefinitely adding /. to the temporary source and destination paths when the directory entry . is read, which is present in all directories. Instead, you should skip the . and .. entries.
Another error is the dimensioning of the temporary paths:
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
The arrays are made just long enough to hold the original paths, though sub-directory names are then appended, overflowing the arrays. Better:
char tempsrc[PATH_MAX];
char tempdest[PATH_MAX];

I'm getting a really odd timing error, where something is executing before I believe it should

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int c, n, E, b, s, v, t, opt, valid = 0;
char current = '\0';
char previous = '\0';
FILE *fp;
/* -n numbers lines
* -E appends a dollar sign to line ends
* -b numbers only non-blank lines
* -s squeezes multiple blank lines down to 1
* -v displays control chars, excluding tab
* -t includes tab in the above
* -e is the same as -E and -v
*/
int setFlags(int argc, char *argv[]) {
int op;
while ((op = getopt(argc, argv, "nEbsvte")) != -1) {
switch (op) {
case 'n': {
n = 1;
break;
} case 'E': {
E = 1;
break;
} case 'b': {
b = 1;
break;
} case 's': {
s = 1;
break;
} case 'v': {
v = 1;
break;
} case 't': {
t = 1;
break;
} case 'e': {
E = 1;
v = 1;
break;
} case '?': {
//fprintf(stderr, "Option `-%c` is not valid.\n", optopt);
return EXIT_FAILURE;
} default: {
abort();
}
}
}
opt = optind;
if(n == 1) {
b = 0;
}
return EXIT_SUCCESS;
}
int checkFile(char *path) {
if (access(path, R_OK) == 0) {
return EXIT_SUCCESS;
} else {
fprintf(stderr, "cat: %s: %s\n", argv[i], strerror(errno));
errno = 0;
return EXIT_FAILURE;
}
}
int doPrint(char *path) {
if (strcmp(path, "stdin") == 0) {
fp = stdin;
} else {
if (checkFile(path) == 1) {
return EXIT_FAILURE;
} else {
fp = fopen(path, "r");
}
}
while ((c = fgetc(fp)) != EOF) {
putchar(c);
}
fclose(fp);
return EXIT_SUCCESS;
}
int main (int argc, char *argv[]) {
if (setFlags(argc, argv) == 1) {
fprintf(stderr, "The program has terminated with an error.\n"
"An invalid option was specified.\n");
return EXIT_FAILURE;
} else {
if ((argc - opt) == 0) {
doPrint("stdin");
} else {
for(int i = opt; i < argc; i++) {
doPrint(argv[i]);
}
}
}
}
I'm getting a really crazy bug, where my program outputs the error line in checkFile, before it finishes writing the contents of the file (always one chat before the end).
It's driving me insane, and no matter where I move that piece of code, it doesn't work as intended.
I'm sure the answer is probably trivial, but it has me stumped. I'd even thrown in sleeps and various other things just before output finished, and it would throw the error, THEN sleep, THEN print the final character.
Any help?
When using printf, stdout output is buffered by default. This means it can be interleaved with other output, often from stderr. stderr is unbuffered by default so that it's output is printed immediately as would normally be desired when an error occurs.
Interleaving can be fixed with judicious use of fflush or by turning off file buffering of stdout using setbuf. Be sure to read the man pages for setbuf as there are some caveats.
In this case, adding fflush(stdout) at the end of the doPrint function should fix the "problem".

Recursively Remove Directories

I've tried several times to write a function to remove directories and the files within the directories, like rm -r, but I haven't managed to do it. The technique I've tried is:
/* rm command */
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define DEBUG
int rm_file(const char **argv);
int rm_tree(const char **argv);
void usage(void);
int rflag = 0;
int main(int argc, char *argv[])
{
int ch;
while((ch = getopt(argc, argv, "Rr")) != -1) {
switch(ch) {
case 'R':
case 'r':
rflag = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
while(*argv) {
if(rflag)
rm_tree(argv);
else
rm_file(argv);
argv++;
}
return 0;
}
int rm_tree(const char **argv)
{
FTS *ftsp;
FTSENT *ftsent;
if((ftsp = fts_open(argv, 0, NULL)) == NULL) {
fprintf(stderr, "error: rm: can't stat directory\n");
return 1;
}
while((ftsent = fts_read(ftsp)) != NULL) {
switch(ftsent->fts_info) {
case FTS_DNR:
fprintf(stderr, "error: rm: can't stat directory\n");
break;
#ifndef DEBUG
case FTS_D:
rm_tree(&ftsent->fts_accpath);
break;
#endif
case FTS_F:
if(unlink(ftsent->fts_accpath) == -1) {
fprintf(stderr, "error: rm: can't remove file\n");
}
break;
case FTS_SL:
if(unlink(ftsent->fts_accpath) == -1) {
fprintf(stderr, "error: rm: can't remove file\n");
}
break;
default:
if(unlink(ftsent->fts_accpath) == -1) {
fprintf(stderr, "error: rm: can't remove file\n");
}
break;
}
}
if(rmdir(*argv) == -1) {
fprintf(stderr, "error: rm: can't remove directory\n");
return 1;
}
return 0;
}
int rm_file(const char **argv)
{
struct stat st;
if(lstat(*argv, &st) == -1) {
fprintf(stderr, "error: rm: can't stat file\n");
return 1;
}
if(S_ISDIR(st.st_mode)) {
fprintf(stderr, "error: rm: can't remove directory\n");
return 1;
}
if(unlink(*argv) == -1) {
fprintf(stderr, "error: rm: can't remove file\n");
return 1;
}
return 0;
}
void usage(void)
{
fprintf(stderr, "usage: rm file1 file2\n");
exit(1);
}
But invariably, I get a segmentation fault or it just doesn't work. Am I looking in the right direction? I've tried using the ftw() functions and the opendir() functions, but I just haven't been able to figure out how to get this to work. I would appreciate it if someone could help.
The code included in the debug tags is where it tends to fail.
Take a look at how it is done in practice by analysing source code of rm in open source operating systems, e.g. OpenBSD (look for rm_tree).

Resources