Segmentation fault when I change directory in C - c

I want to make a program that imitates the use of cd in UNIX. Obviously the best option is chdir. However when the user types cd /home I get Segmentation fault. When I use gdb, it prints:
Program received signal SIGSEGV, Segmentation fault. __rawmemchr_avx2 () at ../sysdeps/x86_64/multiarch/memchr-avx2.S:61
61 ../sysdeps/x86_64/multiarch/memchr-avx2.S: The file of directory does not exist.
The code looks like this:
void cd(char buff[]){
if(chdir(buff)==-1){
printf("Problem with directory\n");
}
}
int main(int argc, char *argv[]){
char* token;
char buffer[256];
printf("Welcome user\n");
sscanf("%s",buffer);
token=strtok(buff," ");
if(strcmp(token,"cd")==0||strcmp(token,"cd\n")==0){
cd(strtok(NULL," ");
}
return 0;
}
Than you for your time.

You have made a few syntactic and logical mistakes inside the provided code, like for example buff instead of buffer in main()and sscanf instead of scanf for giving the input string.
Also, you wrote cd(strtok(NULL," "); but a closing brace is missing for this statement to compile: cd(strtok(NULL," "));.
I've corrected the code and the output file runs fine on my platform - with GCC on Ubuntu GNU/Linux.
Here is the corrected code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void cd(char buff[]){
if(chdir(buff)==-1){
printf("Problem with directory\n");
}
}
int main(int argc, char *argv[]){
char* token;
char buffer[256];
printf("Welcome user\n");
scanf("%s",buffer);
token=strtok(buffer," ");
if(strcmp(token,"cd")==0||strcmp(token,"cd\n")==0){
cd(strtok(NULL," "));
}
return 0;
}
Try it with this.

This code has several problems:
1) even if sscanf is swapped for scanf, it does not do what you probably expect it to (read the whole line inserted by the user). scanf with %s will read up to the first whitespace. So, your buffer will actually contain cd\0 instead of cd /home\0 like you expect it to. Use fgets instead.
2) You must check that strtok does not return a NULL pointer. This is what is currently causing your segfault.
Something like this:
void cd(char buff[]) {
if(chdir(buff) == -1) {
printf("Problem with directory\n");
}
}
int main(int argc, char *argv[]){
char* token;
char buffer[256];
printf("Welcome user\n");
// reads the whole line into buffer
fgets(buffer, 256, stdin);
token = strtok(buffer, " ");
if (strcmp(token, "cd") == 0){
token = strtok(NULL," ");
// we must check if there are any tokens left
if (token != NULL) {
// we must remove the trailing newline character that is included by fgets
cd(strtok(token, "\n"));
}
}
return 0;
}

Related

Making a terminal in c

When I run this c snippet, it outputs something really random every time, and then segfaults...
Code:
#include <stdio.h>
#include <stdlib.h>
int parse(void) {
int i = 0;
int system(const char *command);
char line[1024];
scanf("%[^\n]", line);
system(line);
do {
line[i] = "\0";
i++;
} while (i != 1024);
parse();
}
int main(void) {
parse();
return 0;
}
What I expected was a prompt, and when any shell command is entered (I used pwd for my testing), the output of the command prints and the prompt returns. And this is what actually happened:
Output:
> pwd
/home/runner/c-test
sh: 1: �: not found
sh: 1: : not found
sh: 1: ׀: not found
signal: segmentation fault (core dumped)
Print prompt
Do not use scanf
Use static storage duration buffer
#include <stdio.h>
#include <stdlib.h>
int parse(void)
{
static char line[1024];
while(1)
{
printf(">>>");
if(!fgets(line, 1024, stdin)) return 1;
system(line);
}
}
int main(void) {
parse();
}
https://www.onlinegdb.com/wmPB3ZGNQ
The reason for your crash is most likely explained by the following:
scanf("%[^\n]", line);
means keep reading until there is a newline in the input stream. So once it completes the next character in the input stream is a newline.
The next time you do
scanf("%[^\n]", line);
that newline is still the first character, so the scanf will return without waiting for the user to type any input.
Since you are doing recursion this will happen again and again and again.... Then most likely the system crashes due to stack overflow after a while.
Solution: Read that newline from the input stream before calling scanf again.
Besides that you should:
Remove int system(const char *command);
Put a maximum field width on scanf
Check the return value of scanf
Change "\0" to '\0' (or delete the whole do-while loop as you don't need it)
Use a while(1) { ... } loop instead of recursive calls

Do something when a char variable has a string "cd" in C (Newbie question)

I am very new to C and I'm writing something that will eventually be a shell or at least something like that. I have a char variable command and I have an if-statement that executes (or at least should) function cd()when char command has "cd" as a string. But it doesn't work for some reason and always executes cd.
Sorry if the explenation is trash but english is not my native language and I don't speak it well. Anyways, here is the code (please ignore that chdir doesnt do anything for now):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int loop=1;
char command[512];
while (loop == 1) {
FILE *command_file;
command_file = fopen("/tmp/EXECUTE", "w");
printf("SHELL > ");
fgets(command, sizeof(command), stdin);
fprintf(command_file, "%s", command);
if (strcpy(command, "cd")) {
cd();
}
else {
printf("%s", command);
}
fclose(command_file);
execution();
}
}
void execution() {
char r;
FILE *exec_file;
exec_file = fopen("/tmp/EXECUTE", "r");
system("sh /tmp/EXECUTE");
}
void cd() {
char path;
printf("Enter a path: ");
path = getc(stdin);
chdir();
}
Sorry if the code is a bit cringy but I really need help! If you want just the if statement:
if (strcpy(command, "cd")) {
cd();
}
else {
printf("%s", command);
}
There are two problems with your code:
The fgets reads and includes the newline in the string. So if the input is cd followed by a newline then fgets will put "cd\n" in the buffer.
A Simple way to remove the newline is with the strcspn function:
command[strcspn(command, "\n")] = 0;
The second problem is that strcmp returns zero (i.e. false) when the two strings matches. So your comparison should be:
if (strcmp(command, "cd") == 0)
Oh, and as mentioned in a comment, you should use strcmp to compare strings, not strcpy which is string copy.

C strtok() and strcmp() issues

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int args, char* argv[])
{
const int CBUFF = 1024;
char input[CBUFF];
char wkdir[CBUFF];
char* command;
printf("Welcome to MyShell...\n");
while(1)
{
getcwd(wkdir, CBUFF);
printf("%s ? ", wkdir);
fgets(input, CBUFF, stdin);
command = strtok(input, " ");
if(strcmp(command, "cd") == 0)
{
char* path;
path = strtok(NULL, " ");
if(chdir(path) != 0)
{
printf("ERROR: COULD NOT CHANGE DIRECTORY TO SPECIFIED PATH");
}
}
if(strcmp(command, "exit") == 0) break;
}
return 0;
}
I am running into an issue creating a very simple command shell in C. The input is only being read the way I want it too when I add a space after my directive. I know that it has something to do with my improper use of the strtok() function but am not able to figure out what I am doing wrong. I have read the documentation of <string.h> and am turning up blank.
Behavior I want:
Directive "exit" to exit from program.
Current behavior:
Must add space after directive to get it to parse correctly ie. "exit " or "cd " is entered.
You left the trailing newline in the buffer. Get rid of it.
char *got = fgets(input, CBUFF, stdin);
if (!got) return ; /* EOF -- treat like exit */
size_t gotlen = strlen(got);
if (got[gotlen] == '\n') got[gotlen] = 0;

Segmentation Fault With Strcmp With One Input

I am having an issue with the following code.
I have a global variable
char tokens[512][80];
Along with code:
int main(int argc, char** argv) {
char *input = malloc(sizeof(char) * 80);
while (1) {
printf("mini-shell>");
fgets(input, 80, stdin);
parse(input);
if (strcmp(tokens[0], "cd") == 0) {
cd();
}
else if (strcmp(tokens[0], "exit") == 0) {
exit(1);
}
}
}
void parse(char str[]) {
int index = 0;
char* str_ptr = strtok(str, " ");
while (str_ptr != NULL) {
strcpy(tokens[index], str_ptr);
str_ptr = strtok(NULL, " \0\r\n");
//printf("%d\n", index);
index = index + 1;
}
}
I found that if I enter exit for stdin I get a Segmentation fault, but if I enter cd .. for stdin I don't. Why is this so?
We don't know what the definition of the cd() function is, but there are a number of things that you may wish to consider in this program.
First, I don't believe there's any benefit to dynamically allocating 80 bytes of memory for the input buffer when you can easily do so automatically on the stack with char input[80]; - this is free and easy and requires no deallocation when you're done.
If you do this, you derive the size with fgets(input, sizeof input, stdin) where if you change the size of your input line from 80 to some other number, you only have to change it once: the sizeof on an array pulls the size directly.
Your parse() routine needs a little bit of help also. It's a really good idea to declare the function via the extern as shown so that when the compiler sees you call the function in the loop (right after the fgets), it knows the parameter and return types. Otherwise it has to make assumptions.
Because parse() is splitting apart the line you read from input, it's not required to copy the strings to some other place, so you can turn tokens from a multi-dimensional array into a simple array of pointers. As you run strtok() through the line to split up the parameters, you can store just the pointer, knowing that they will be pointing to stable data until the next fgets().
Also: your code does not strictly require or use this, but adding a NULL pointer to the end of the tokens list is a really good idea: otherwise, how does the caller know how many parameters were actually entered? This code checks whether the user entered just a blank line or not.
We've also change the loop around a little bit so the strtok() is called just once instead of twice, including the \n as noted in the comments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *tokens[512];
extern void parse(char *str);
int main(int argc, char** argv) {
char input[80];
while (1) {
printf("mini-shell> "); fflush(stdout); // make sure user sees prompt
fgets(input, sizeof input, stdin);
parse(input);
if (tokens[0] == NULL) continue; // user entered blank line
if (strcmp(tokens[0], "cd") == 0) {
cd();
}
else if (strcmp(tokens[0], "exit") == 0) {
exit(1);
}
}
}
void parse(char *str) {
int index = 0;
char* str_ptr;
while ( (str_ptr = strtok(str, " \n")) != NULL)
{
tokens[index++] = str_ptr;
str = NULL; // for next strtok() loop
}
tokens[index] = NULL;
}

Config file parsing string matching error in c

While I am aware there are libraries for config file parsing I have tried to write my own implementation. The problem is that I can find the config option but comparing the string before the delimeter failes when I try to compare it with the thing I am searching for. I need to comare it with the thing I am searching for becasue my program allows things like Test2 and Test3 because it cannot check if there are characters before or after the word Test. The compare allways failes and I cannot figure out why.
Here is my code:
Main.c
#include <stdio.h>
#include <stdlib.h>
void Parser(char *CONFIG_FILE, int *P_VALUE, char *STRING_TO_LOOK_FOR);
int main(){
int VALUE;
Parser("config.txt", &VALUE, "Test");
printf("%d \n", VALUE);
}
Parser.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Parser(char *CONFIG_FILE, int *P_VALUE, char *STRING_TO_LOOK_FOR){
FILE *FP=fopen(CONFIG_FILE,"a+");
char TMP[256]={0x0};
int i = 1;
while(FP!=NULL && fgets(TMP, sizeof(TMP), FP)!=NULL){ //Loop through every line
i=i+1; //Increment the line number
if (strstr(TMP, STRING_TO_LOOK_FOR)){ //Is the term im looking for in this line
char *NAME_OF_CONFIG_STR = strtok(TMP, "= "); //look for delimiter
char *STRVALUE = strtok(NULL, "= "); //Get everything past the delimiter
char *P_PTR;
char *pos;
if ((pos=strchr(NAME_OF_CONFIG_STR, '\n')) != NULL){ //attempt remove \n doesn't work
*pos = '\0';
}
if(strcmp(STRING_TO_LOOK_FOR, NAME_OF_CONFIG_STR) == 0){ //try to check the two are the same
*P_VALUE = strtol(STRVALUE, &P_PTR, 10); //Returns an integer to main of the value
}
}
}
if(FP != NULL){
fclose(FP);
}
}
config.txt:
Test= 1234
Test2= 5678
Test3= 9012
Thanks to BLUEPIXY and the demo they created this problem has been solved. The issue was in the gcc comiler options I had forgotten -std=99 somehow this caused the program to behave correctly.

Resources