I am working on a project in C. It is a primitive file system shell and one of commands can either take in a string after it or not. Here is how I am reading in commands from stdin. (This way is specified by my instructor):
fsys* f = newFileSystem();
char cmd[21];
char path[1001];
while(scanf("%s", cmd) > 0){
if(strcmp(cmd, "ls") == 0){
// this is probably the wrong way to go about it but...
if(fgets(path, 1001, stdin)){ // 1001 is max path length
strtok(path, "\n"); // doesn't remove if path is only \n
// fgets reads in \n character and it affects output
// later, so getting rid of it now
strtok(path, " "); // doesn't remove space between ls and path name
fs_ls(f, path);
}
}
else if(strcmp(cmd, "pwd") == 0){
// prints path to cwd beginning at root
fs_pwd(f);
// some other commands in here
else{
printf("Command not recognized.");
}
}
So ls can either take in no path (defaults to current working directory) or can take in a path and list files and directories at that location.
What can I write within the if statement "if(strcmp(cmd, "ls") == 0)" for the system to check if there is a path after ls or not and execute ls correctly?
Related
So I am using the open function in C to open a target file, and if it does not exist, I will create it. I am redirecting stdout from the terminal into this file. When I run my program, it creates a new file with the name that I type into the shell, but appends a "?" to the end. Can someone help me figure out how to remove that?
My code is below
// Take output from ls as input into the next argument.
command = strtok(NULL, " "); // Holds the value for the destination file.
printf("%s\n", command);
int targetFD = open(command, O_WRONLY | O_CREAT | O_TRUNC, 0700);
if (targetFD == -1)
{
perror("open()");
exit(1);
}
printf("The file descriptor for targetFD is %d\n", targetFD);
int result = dup2(targetFD, 1);
if (result == -1)
{
perror("dup2");
exit(2);
}
ls(); // instead of printing ls to the terminal, it gets written to the file.
Here is an image of a sample execution. Notice how junk.txt file already exists...I want my program to redirect "ls" into that file or create a new one of the file does not exist.
sample program execution
I bet the ? is not a literal ? character, but the way that your version of ls displays a filename containing a non-printable character, e.g. if you use GNU ls and have the -q option enabled by default.
I also note that in your sample output, there is an extra blank line between junk.txt and The file descriptor for targetFD. You only printed one newline after command, so I suspect that the string command itself ends with a \n. That would fit if it was parsed from a string that ended with \n (e.g. a line read with fgets). So you actually created a file named junk.txt\n, and ls prints the newline character as ?.
Perhaps you wanted to use " \n" as the delimiter string for strtok, so that a newline will also be treated as a delimiter and not be included in the token string.
I'm trying to write a simple shell, it all works except the redirect with '>'. I was advised to parse my input string from the user using a delimiter of ">". The output string then has two elements, output[0] will be the entire command that user enters including the arguments. output[1] will be the filename.
My issue is that it creates the file specified by output[1], however it writes nothing to it! Even if I put a printf to stdout, it writes to the terminal instead.
else if(*delim == '>'){
int f = open(output_str[1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
int stdout_sv = dup(1); // Saving the current stdout descriptor for restoring later.
if(errno != 0){
perror("");
}
dup2(f,1);
execvp(output_str[0], output_str);
printf("Sample Line to file.");
dup2(stdout_sv, 1); // Restoring stdout
close(f);
}
This results in the following output:
[04/04 15:55]# ls > test.txt
output_str[0] = ls
output_str[1] = test.txt
Sample Line to file.[04/04 15:55]#
I'm really confused as to why the stdout isn't being redirected towards the output file(test.txt). I mean the output file is correct.
Note: I realise there is a space before test.txt, I have tried parsing with " >" which removes the space in the output_str[1], the file still ends up empty.
I work on Xcode and I have a simple function that opens a file using open in C.
void mfs_workwith() {
char *token, *temp_token;
char *search = ".";
temp_token = (char*)malloc(sizeof(char)*strlen(cc[1]));
strcpy(temp_token, cc[1]);
if ((token = strtok(temp_token, search)) == NULL) {
printf("mfs_workwith command is only used with mfs type files e.g. example.mfs \n");
} else if ((token = strtok(NULL, " \n\0")) == NULL) {
printf("mfs_workwith command is only used with mfs type files e.g. example.mfs \n");
} else if (strcmp(token, "mfs") == 0) {
filename = malloc(sizeof(char)*strlen(cc[1]));
strcpy(filename, cc[1]);
if ((file_mfs = open(filename, O_RDWR)) == -1) {
perror("open error");
} else {
printf("open successful \n");
}
}
}
The name of the file is stored in a global array and then copied into local buffers in order to tokenize and check if it has the right format (.mfs).
Then if everything is ok I make a fresh copy of the name of the file and call open with it.
My problem is that when I run my program in terminal it runs fine, prints open successful and then continues. But when I try to run it in Xcode it fails with this error:
No such file or directory
I am giving the input file.mfs which is the name of a file in the same directory.
Am I missing something obvious?
I found the problem thanks to iharob's comment. It seems xcode has a hard time opening relative paths since it uses a different file while running the program. There is a relative discussion here:
Open method opens files with full path only C++
thanks again everyone.
This:
filename = malloc(sizeof(char)*strlen(cc[1]));
strcpy(filename, cc[1]);
is broken, it fails to allocate room for the string's terminator, so it causes buffer overflow and undefined behavior.
Also, you never need to scale by sizeof (char), that's always 1. It should be:
filename = malloc(strlen(cc[1]) + 1);
strpcy(filename, cc[1]);
or, if you have it, just:
filename = strdup(cc[1]);
I am writing a program that asks the user for a linux bash command and then stores them in pointer arrays (kind of like char *argv[]). The program must then make a check if this command is a normal bash command or a cd (change directory) command. If its a cd command then it should use something like chdir(). If the command is anything else I wanna use some variation of the exec() system call to execute that command.
However I am not succeeding with the first part (chdir()).
int ii=-1
printf("Enter the command: ");
fgets(command, 100, stdin);
command[strlen(command)-1]=0;
printf("Command = %s\n", command);
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
printf("I am inside CD now.\n");
cd_dump[0] = strtok(command," ");
while(sub_string[++ii]=strtok(NULL, " ") != NULL)
{
printf("%s\n", sub_string[0]);
}
chdir(sub_string[0]);
}
Edit:
I have also tried the following if statement without luck.
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
printf("I am inside CD now.\n");
chdir(command+3);
}
Sadly the program isnĀ“t doing what I want it to, and even after hours trying to solve the issue I have no idea why. What have I done wrong? Also if I input cd /home/ why does the output result in sub_string[0] end up with an extra "Enter key" on the output? Does strtok save the Enter key into the string?
Any help on the subject is very much appreciated.
Calling chdir() only affects the current process, not its parent process.
If you chdir() and exit immediately, it is pointless - the shell you call it from keeps its old cwd. That's why cd is always a shell builtin.
Use
char buffer[PATH_MAX];
if (getcwd(buffer, sizeof buffer) >= 0) {
printf("Old wd: %s\n", buffer);
}
chdir(command+3);
if (getcwd(buffer, sizeof buffer) >= 0) {
printf("New wd: %s\n", buffer);
}
to verify chdir() works correctly.
I think I'd do something like this:
if (command[0]=='c' && command[1]=='d' && command[2]==' ')
{
for(i=2, i++, command[i]!=' '); /* Skip to nonspace */
chdir(command+i);
}
I have never used stat() before and am not sure what is going wrong.
I have a server program that takes a GET request and parses out the file path. I also have a client program in the same directory that sends the GET request. The server program is taking the GET request and parsing out the file path correctly. The path to the directory where both programs are is: ~/asimes2/hw2/
If I have the client program send: GET /Makefile HTTP/1.0\r\n\r\n
Then the server program receives the same thing. I have two printf()s to confirm I am parsing the file path correctly and to see the full path. It outputs:
File path = '/Makefile'
Full path = '~/asimes2/hw2/Makefile'
NOT FOUND!
Makefile does exist in ~/asimes/hw2. Here is the code:
// Alex: Parse the PATH from the GET request using httpGet
char* filePath, * pathStart = strchr(httpGet, '/');
if (pathStart != NULL) {
// Alex: Increment to the first '/'
httpGet += (int)(pathStart-httpGet);
// Alex: Assuming " HTTP" is not a part of the PATH, this finds the end of the PATH
char* pathEnd = strstr(httpGet, " HTTP");
if (pathEnd != NULL) {
int endLoc = (int)(pathEnd-httpGet);
filePath = (char*)malloc((endLoc+1)*sizeof(char));
strncpy(filePath, httpGet, endLoc);
filePath[endLoc] = '\0';
}
else errorMessageExit("The GET request was not formatted as expected");
}
else errorMessageExit("The GET request was not formatted as expected");
printf("File path = '%s'\n", filePath);
char* fullPath = (char*)malloc((14+strlen(filePath))*sizeof(char));
strcpy(fullPath, "~/asimes2/hw2");
strcat(fullPath, filePath);
printf("Full path = '%s'\n", fullPath);
struct stat fileStat;
if (stat(fullPath, &fileStat) == -1) printf("NOT FOUND!\n");
else printf("HOORAY\n");
My answer only addresses your issue with the file name.
The shell interprets this: ~/asimes2/hw2/Makefile
It's not a valid filename to pass to stat() with the ~
You should be able replace the leading ~ with something link /home/ or wherever the actual home directory is.
Try this:
char* fullPath = malloc((80+strlen(filePath))*sizeof(char));
strcpy(fullPath, "/home/ubuntu/asimes2/hw2");
strcat(fullPath, filePath);
printf("Full path = '%s'\n", fullPath);
You need to glob pathnames, see glob(7). You could perhaps use wordexp(3) to expand the ~, $ etc...
HTTP servers usually have some configurable document root, perhaps /var/www. Then the URL pathname /Makefile is transformed to /var/www/Makefile
You should perhaps use some HTTP server library like libonion
And you should use errno at least for debugging purposes on syscall failure, so code
if (stat(fullPath, &fileStat) == -1)
printf("%s NOT FOUND! %s\n", fullPath, strerror(errno));
Perhaps chroot(2) might interest you. And read Advanced Linux Programming!