How to check dynamic allocation - c

How can i check if i am using right the dynamic allocation in my C code.
It is an assignment for uni. When i put my code in the auto corrector system of my professor i get an error for dynamic allocation. My code :
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
int main( )
{
for(;;)
{
char *cmd,*splitcmd;
//*pr0,*pr1,*pr2 ;
size_t bufsize = 1024;
char pr1[bufsize];
char pr2[bufsize];
char pr0[bufsize];
//char pr3[40];
int i,j,nargc=0,characters;
char **cmdArray;
//size_t bufsize = 1024;
// size_t bufsizecmd =1024;
pid_t pid,wpid;
int status = 0;
char pr='$';
char exit1[10]="exit";
char *path;
path = getenv("PATH");
putchar(pr);
cmd = malloc(bufsize * sizeof*cmd);
characters = getline(&cmd,&bufsize,stdin);
//printf("cmd===> %s characters===> %d \n",cmd,characters);
if(cmd[characters-1]=='\n' )
{
cmd[characters-1]='\0';
characters--;
}
//printf("cmd===> %s characters===> %d \n",cmd,characters);
cmdArray = malloc(bufsize*sizeof*cmdArray );
for ( i = 0; i < bufsize; i++ )
{
cmdArray[i]=malloc(bufsize*sizeof*cmdArray );
}
splitcmd=strtok(cmd," ");
// printf(" cmd==== %s\n",cmd);
while((splitcmd))
{
strcpy(cmdArray[nargc],splitcmd);
if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ')
cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='\0';
//printf(" nargc====%d cmdArray===[%s] \n",nargc,cmdArray[nargc]);
nargc++;
splitcmd = strtok(NULL," ");
}
//printf(" pr0 %s \n",pr0);
//printf(" pr1 %s \n",pr1);
//printf(" pr2 %s \n",pr2);
strcpy(pr0,cmdArray[0]);
if (strcmp( pr0, exit1) == 0 )
{
//printf("---------->Eksodos apo to programma<---------- \n");
free(cmd);
return (0);
exit(0);
//return (0);
}
else
{
if ((pid=fork()) == 0)
{
if(nargc ==1 )
{
strcpy(pr0,cmdArray[0]);
char *argv[] = {path,NULL};
execvp(pr0,argv);
for ( i = 0; i < bufsize; i++)
{
free(cmdArray[i]);
}
free(cmdArray);
free(cmd);
exit(0);
}
else if(nargc==2)
{
strcpy(pr0,cmdArray[0]);
strcpy(pr1,cmdArray[1]);
char *argv[] = {pr0,pr1,NULL};
execvp(pr0,argv);
exit(0);
for ( i = 0; i < bufsize; i++)
{
free(cmdArray[i]);
}
free(cmdArray);
free(cmd);
exit(0);
}
else
{
strcpy(pr0,cmdArray[0]);
strcpy(pr1,cmdArray[1]);
strcpy(pr2,cmdArray[2]);
//printf("cmdddddddd****====%s \n",*cmdArray);
char *argv[] = {pr0,pr1,pr2,NULL};
execvp(argv[0],argv);
for ( i = 0; i < bufsize; i++)
{
free(cmdArray[i]);
}
free(cmdArray);
free(cmd);
exit(0);
}
}
wait(&status);
}
}
}

There is no corresponding free() for cmd = (char *)malloc(bufsize * sizeof(char));.
Also, this code block:
strcpy(pr0,cmdArray[0]);
if (strcmp( pr0, exit1) == 0 )
{
//printf("---------->Eksodos apo to programma<---------- \n");
free(cmd);
return (0);
exit(0);
//return (0);
}
will need this
for ( i = 0; i < bufsize; i++)
{
free(cmdArray[i]);
}
free(cmdArray);
before the
free(cmd);
In this code block, there are two exit() calls:
else if(nargc==2)
{
strcpy(pr0,cmdArray[0]);
strcpy(pr1,cmdArray[1]);
char *argv[] = {pr0,pr1,NULL};
execvp(pr0,argv);
exit(0);
for ( i = 0; i < bufsize; i++)
{
free(cmdArray[i]);
}
free(cmdArray);
free(cmd);
exit(0);
}
The one immediately after the execvp(pr0,argv); prevents any of the free() calls from being executed. It needs to be removed.

Related

How to see the current path in linux shell using c++?

I am creating a shell program that has the ability to change directories and exit the shell. Everything is working as it should. I have a question about showing the current directory/path that I am in. When I compile & run my code. I am in my shell loop. My cursor represents ash > I want that cursor to represent the current path that the user is in.
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int ash_exit(char **args);
int ash_cd(char **args);
char const *builtin_str[] = {
"exit", "cd"};
int (*builtin_func[])(char **) = {
&ash_exit, &ash_cd};
int ash_num_builtins()
{
return sizeof(builtin_str) / sizeof(char *);
}
/**
Bultin command: change directory.
args List of args. args[0] is "cd". args[1] is the directory.
Always returns 1, to continue executing.
*/
int ash_cd(char **args)
{
if (args[1] == NULL)
{
fprintf(stderr, "ash: expected argument to \"cd\"\n");
}
else
{
if (chdir(args[1]) != 0)
{
perror("ash");
}
}
return 1;
}
int ash_exit(char **args)
{
return 0;
}
int ash_launch(char **args)
{
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
// Child process
if (execvp(args[0], args) == -1)
{
perror("ash");
}
exit(EXIT_FAILURE);
}
else if (pid < 0)
{
// Error forking
perror("ash");
}
else
{
// Parent process
do
{
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
int ash_execute(char **args)
{
int i;
if (args[0] == NULL)
{
// An empty command was entered.
return 1;
}
for (i = 0; i < ash_num_builtins(); i++)
{
if (strcmp(args[0], builtin_str[i]) == 0)
{
return (*builtin_func[i])(args);
}
}
return ash_launch(args);
}
char *ash_read_line(void)
{
char *line = NULL;
ssize_t bufsize = 0; // have getline allocate a buffer for us
if (getline(&line, (unsigned long *)&bufsize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS); // We recieved an EOF
}
else
{
perror("readline");
exit(EXIT_FAILURE);
}
}
return line;
}
#define ASH_TOK_BUFSIZE 64
#define ASH_TOK_DELIM " \t\r\n\a"
/**
Split a line into tokens
line The line.
return Null-terminated array of tokens.
*/
char **ash_split_line(char *line)
{
int bufsize = ASH_TOK_BUFSIZE, position = 0;
char **tokens = (char **)malloc(bufsize * sizeof(char *));
char *token, **tokens_backup;
if (!tokens)
{
fprintf(stderr, "ash: allocation error\n");
exit(EXIT_FAILURE);
}
token = strtok(line, ASH_TOK_DELIM);
while (token != NULL)
{
tokens[position] = token;
position++;
if (position >= bufsize)
{
bufsize += ASH_TOK_BUFSIZE;
tokens_backup = tokens;
tokens = (char **)realloc(tokens, bufsize * sizeof(char *));
if (!tokens)
{
free(tokens_backup);
fprintf(stderr, "ash: allocation error\n");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, ASH_TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}
void ash_loop(void)
{
char *line;
char **args;
int status;
do
{
printf("ash > ");
line = ash_read_line();
args = ash_split_line(line);
status = ash_execute(args);
free(line);
free(args);
} while (status);
}
int main(int argc, char *argv[])
{
ash_loop();
return EXIT_SUCCESS;
}
getcwd(3) gives you the current path:
char buf[PATH_MAX] = {0};
getcwd(buf, sizeof buf);
printf("ash %s > ", buf);
Need to include <linux/limits.h> for PATH_MAX.

is there a replacement for argc and argv

I have a C program here where a warehouse is managed. I want to use argc and argv in this code, because the program always expects the commands as call parameters, not as interactive input. And I want to be able to enter them as interactive input.
How should it be changed? I am completely new to C or programming in general.
sorry in the code some words are not in english
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMELENGTH 100
#define DBSIZE 1000
#define DBNAME "database.bin"
struct Artikel
{
char artikel[NAMELENGTH + 1];
int anzahl;
};
struct Artikel db[DBSIZE];
void fehler(const char *text)
{
fprintf(stderr, "Fehler: %s!\n", text);
exit(1);
}
void check_artikel(char *artikel)
{
if (!artikel || strlen(artikel) > NAMELENGTH)
fehler("Artikel zu lang");
}
void db_load()
{
FILE *input = fopen(DBNAME, "rb");
if (!input)
fehler("Datenbank zum Lesen öffnen fehlgeschlagen");
size_t size = fread(db, 1, sizeof(db), input);
if (size != sizeof(db))
fehler("Datenbank nicht komplett geladen");
fclose(input);
}
void db_save()
{
FILE *output = fopen(DBNAME, "wb");
if (!output)
fehler("Datenbank zum Schreiben öffnen fehlgelschlagen");
size_t size = fwrite(db, 1, sizeof(db), output);
if (size != sizeof(db))
fehler("Datenbank nicht komplett geschrieben");
fclose(output);
}
void db_clear()
{
for (int i = 0; i < DBSIZE; i++)
{
db[i].anzahl = 0;
}
}
int db_size()
{
int size = 0;
for (int i = 0; i < DBSIZE; i++)
size += db[i].anzahl ? 1 : 0;
return size;
}
int db_find(char *artikel)
{
for (int i = 0; i < DBSIZE; i++)
if (db[i].anzahl > 0 && !strcasecmp(db[i].artikel, artikel))
return i;
return -1;
}
void db_add(char *artikel, int anzahl)
{
int found = db_find(artikel);
if (found >= 0)
{
db[found].anzahl += anzahl;
return;
}
for (int i = 0; i < DBSIZE; i++)
if (db[i].anzahl == 0)
{
strcpy(db[i].artikel, artikel);
db[i].anzahl = anzahl;
return;
}
fprintf(stderr, "Datenbank voll!\n");
}
void db_list()
{
if (db_size() == 0)
{
printf("Datenbank ist leer.\n");
return;
}
printf("Anzahl : Artikel\n");
printf("--------:-------------------------------------------------------------\n");
for (int i = 0; i < DBSIZE; i++)
if (db[i].anzahl > 0)
{
printf(" %5d : %s\n", db[i].anzahl, db[i].artikel);
}
}
int main(int argc, char **argv)
{
if (argc < 2)
fehler("Kein Kommando angegeben!\nGültige Kommandos: init, add ANZAHL ARTIKEL, list");
const char *cmd = argv[1];
if (!strcmp(cmd, "init"))
{
db_clear();
db_save();
printf("Datenbank initialisiert.\n");
}
else if (!strcmp(cmd, "list"))
{
db_load();
db_list();
}
else if (!strcmp(cmd, "add"))
{
if (argc < 3)
fehler("Keine Artikelanzahl angegeben");
int anzahl = atoi(argv[2]);
if (anzahl <= 0)
fehler("Artikelanzahl zu klein");
if (argc < 4)
fehler("Kein Artikel angegeben");
char *artikel = argv[3];
check_artikel(artikel);
if (argc > 4)
fehler("Zu viele Eingaben");
db_load();
db_add(artikel, anzahl);
db_save();
printf("Artikel hinzugefügt.\n");
}
else
{
fprintf(stderr, "Unbekanntes Kommando!\n");
return 1;
}
return 0;
}

minishell malloc error with EXC_BAD_ACCESS

Hi I've recently started learning unix system programming.
I'm trying to create a minishell in c but when I run my code,
I always get:
EXC_BAD_ACCESS (code=EXC_I386_GPFLT
Don't really know what's wrong here. Searched online they say it's something wrong with malloc, but I don't see what's wrong.
Can someone help me with this problem?
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include "minishell.h"
char promptString[] = "mysh>";
struct command_t command;
int enviromentlength;
int commandlength;
char *pathv[MAX_PATHS];
//to display the prompt in the front of every line
void printPrompt()
{
printf("%s", promptString);
}
//get the user's command
void readCommand(char *buffer)
{
gets(buffer);
}
//get the environment variable and store in a pathEnvVar
int parsePath( char* dirs[] )
{
char* pathEnvVar;
char* thePath;
int i;
for(i = 0; i < MAX_ARGS; i++)
{
dirs[i] = NULL;
}
i = 0;
//use system call to get the environment variable
pathEnvVar = (char*) getenv("PATH");
//printf("%s\n", pathEnvVar);
thePath = (char*) malloc(strlen(pathEnvVar) + 1);
strcpy(thePath, pathEnvVar);
//splict the variable and store in the pathv
char *temp = strtok(thePath, ":");
dirs[i] = temp;
while(temp != NULL)
{
i++;
temp = strtok(NULL, ":");
if(temp == NULL)
{
break;
}
else
{
dirs[i] = temp;
}
}
dirs[i+1] = NULL;
return i;
}
//get the user's command and parameters
int parseCommand(char * commandline)
{
int i = 0;
char* temp;
temp = strtok(commandline, " ");
while(temp != NULL)
{
command.argv[i] = temp;
i++;
temp = strtok(NULL, " ");
}
command.argv[i] = NULL;
return i;
}
//input the user's command to
//fix the absolute path of the command
char* lookupPath(char* dir[], char* command[])
{
char* result = NULL;
int i;
//printf("%c\n", *command.argv[0]);
//if the command is already an absolute path
if(*command[0] == '/')
{
result = command[0];
//printf("test\n");
if( access(result, X_OK) == 0)
{
return result;
}
else
{
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//if the command is not an absolute path
else
{
for(i = 0; i < enviromentlength; i++)
{
char *temp = (char *) malloc (30);
strcpy(temp, dir[i]);
strcat(temp, "/");
strcat(temp, command[0]);
result = temp;
if( access(result, X_OK) == 0)
{
return result;
}
}
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//to change the directory and
//display the absolute path of the current directory
void do_cd(char* dir[])
{
char currentdirectory[MAX_PATHS];
if(dir[1] == NULL || (strcmp(dir[1], ".") == 0))
{
printf("director does not change\n");
//printf("The current directory is:%s", currentdirectory);
}
else
{
if(chdir(dir[1]) < 0)
{
printf("change director error\n");
}
else
{
printf("change director success\n");
}
}
getcwd(currentdirectory, MAX_PATHS);
printf("The current directory is:%s\n", currentdirectory);
}
//redirection the result to file
void redirection(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
char* content[commandlength - 1];
char* filename = (char *) malloc(MAX_PATH_LEN);
FILE* fid;
int i = 0;
int stat;
strcpy(filename, commandcontent[position + 1]);
//printf("%s\n", commandcontent[position + 1]);
for(i = 0; i < position; i++)
{
content[i] = commandcontent[i];
//printf("content: %s\n", content[i]);
}
content[i + 1] = NULL;
for(i = 0; i< position + 1; i++)
{
printf("%s\n", content[i]);
}
printf("%s\n", command);
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
fid = open(filename, O_WRONLY || O_CREAT);
close(1);
dup(fid);
close(fid);
execve(command, content, pathv);
}
else
{
wait(&stat);
}
}
//use pipe to run the program
void piperun(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
printf("%s\n%d\n", command, position);
char* firstcommand[position+1];
char* secondcommand[commandlength-position];
char* result = (char *) malloc(MAX_PATH_LEN);
pid_t child;
//the pipe name
int pipeID[2];
int j;
for(j = 0; j< position; j++)
{
firstcommand[j] = commandcontent[j];
printf("%s\n", firstcommand[j]);
}
firstcommand[j] = NULL;
printf("length: %d\n", commandlength-position);
for(j = 0; j < (commandlength-position); j++)
{
secondcommand[j] = commandcontent[position + 1 + j];
printf("second:%s\n",secondcommand[j]);
}
//secondcommand[j+1] = NULL;
result = lookupPath(pathv, secondcommand);
//printf("%s\n", secondcommand[0]);
printf("%s\n", result);
//create pipe "pipeID"
if(pipe(pipeID)==-1)
{
printf("Fail to creat pipe.\n");
}
if((thisChPID=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(thisChPID==0)
{
printf("in the child\n");
close(1);
dup(pipeID[1]);
close(pipeID[0]);
close(pipeID[1]);
if(execve(command, firstcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",firstcommand[0]);
}
}
else
{
child = fork();
if((child=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(child==0)
{
close(0);
dup(pipeID[0]);
close(pipeID[1]);
close(pipeID[0]);
if(execve(result, secondcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",secondcommand[0]);
}
}
else
{
wait(NULL);
}
}
}
int main()
{
char commandLine[LINE_LEN];
int child_pid; //child process id
int stat; //used by parent wait
pid_t thisChPID;
char *arg[MAX_ARGS];
//the flag of redirection, piping and background running
int redirectionsituation = 0;
int pipesituation = 0;
int background = 0;
char * tempchar;
//Command initialization
int i;
for(i = 0; i < MAX_ARGS; i++ )
{
command.argv[i] = (char *) malloc(MAX_ARG_LEN);
}
//get all directories from PATH env var
enviromentlength = parsePath(pathv);
//Main loop
while(TRUE)
{
redirectionsituation = 0;
pipesituation = 0;
background = 0;
//Read the command line
printPrompt();
readCommand(commandLine);
//input nothing
if(commandLine[0] == '\0')
{
continue;
}
//quit the shell?
if((strcmp(commandLine, "exit") == 0) || (strcmp(commandLine, "quit") == 0))
{
break;
}
//if it is background running
if(commandLine[strlen(commandLine) - 1] == '&')
{
printf("backgrond\n");
tempchar = strtok (commandLine, "&");
//strcpy(commandLine, tempchar);
printf("%s\n", tempchar);
background = 1;
}
//Parse the command line
commandlength = parseCommand(commandLine);
//if the command is "cd"
if(strcmp(command.argv[0], "cd") == 0)
{
do_cd(command.argv);
continue;
}
//Get the full path name
command.name = lookupPath(pathv, command.argv);
printf("command name %s\n", command.name);
//report error
if( command.name == NULL)
{
continue; //non-fatal
}
//if redirection is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], ">") == 0)
{
redirectionsituation = 1;
break;
}
}
if(redirectionsituation == 1)
{
redirection(command.name, command.argv, i, thisChPID);
continue;
}
//if pipe is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], "|") == 0)
{
pipesituation = 1;
break;
}
}
if(pipesituation == 1)
{ //run pipe
piperun(command.name, command.argv, i, thisChPID);
continue;
}
//normal running
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
//printf("run again\n");
execve(command.name, command.argv, pathv);
}
else
{
//do not put the process in the background, wait until the child process terminates
if(background == 0)
{
wait(&stat);
}
}
}
return 0;
}
Run it in a debugger and see where you are dereferencing a null.

Segmentation fault using fgets in C

My code is not working and it is when I call fgets in the commandSplit function. I figured this out by printing "Am I here" in multiple places and find that the error at fgets it seems. I may be wrong, but I am pretty sure. I get a segmentation fault and I can not figure out why. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAX_CHARACTERS 512
int Execute(char *a[], int t[], int num) {
int exitShell = 0;
int l = 0;
for (int i = 0; i < num; i++) {
int status;
if (strcmp(a[0], "quit") == 0) {
exitShell = 1;
}
if (t[i] && ((strcmp(a[l], "quit") == 0))) {
exitShell = 1;
}
char *holder[t[i]+1];
for (int j = 0; j < t[i]; j++) {
holder[j] = a[l];
l++;
}
holder[t[i]] = NULL;
pid_t p = fork();
pid_t waiting;
if (p == 0) {
execvp(holder[0], holder);
fprintf(stderr, "Child process could not execvp!\n");
exit(1);
} else {
if (p < 0) {
fprintf(stderr, "Fork FAILED!\n");
} else {
waiting = wait(&status);
printf("Child %d exit with status %d\n", waiting, status);
}
}
for (int g = 0; g < t[i]; g++) {
a[g] = NULL;
}
}
for (int i = 0; i < num; i++) {
t[i] = 0;
}
return exitShell;
}
int commandSplit(char *c, FILE *f, char *a[], int t[]) {
int count = 0;
int emptyfile = 1;
int stat = 0;
int total1 = 0;
char *temp[MAX_CHARACTERS];
if (c != NULL) {
char *readCommands = strtok(c, ";");
while (readCommands != NULL) {
temp[count] = readCommands;
count++;
readCommands = strtok(NULL, ";");
}
for (int i = 0; i < count; i++) {
char *read = strtok(temp[i], " ");
int track1 = 0;
while (read != NULL) {
a[total1] = read;
track1++;
total1++;
read = strtok(NULL, " ");
}
t[i] = track1;
}
stat = Execute(a, t, count);
} else {
char *buildCommands = "";
printf("Am I here???\n");
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
printf("Am I here???\n");
emptyfile = 0;
commandSplit(buildCommands, NULL, a, t);
stat = Execute(a, t, count);
}
if (emptyfile) {
printf("File is empty!\n");
stat = 1;
}
}
printf("Am I here???\n");
return stat;
}
int main(int argc, char *argv[]) {
int exitProgram = 0;
FILE *fileRead = NULL;
if (argc == 2) {
fileRead = fopen(argv[1], "r");
if (fileRead == NULL) {
printf("No such file exists\n");
exitProgram = 1;
}
}
if (argc > 2) {
printf("Incorrect batch mode call\n");
exitProgram = 1;
}
char *args[MAX_CHARACTERS];
int tracker[MAX_CHARACTERS];
while (!exitProgram) {
if (argc == 1) {
char *commands = (char *)(malloc(MAX_CHARACTERS * sizeof(char)));
printf("tinyshell>");
if (fgets(commands, MAX_CHARACTERS, stdin) == NULL) {
exitProgram = 1;
printf("\n");
}
int len;
len = strlen(commands);
if (len > 0 && commands[len-1] == '\n') {
commands[len-1] = '\0';
}
if (len > MAX_CHARACTERS) {
printf("TOO MANY CHARACTERS - MAX: 512\n");
continue;
}
if (strlen(commands) == 0)
continue;
exitProgram = commandSplit(commands, NULL, args, tracker);
} else {
exitProgram = commandSplit(NULL, fileRead, args, tracker);
}
}
fclose(fileRead);
return 0;
}
As commented #Jean-François Fabre , buildCommands points to insufficient space and potential const space;
char *buildCommands = "";
...
// bad code
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
Allocate space with an array or malloc()
char buildCommands[MAX_CHARACTERS];
...
while ((fgets(buildCommands, sizeof buildCommands, f) != NULL) && !stat) {
...
}
// or
char *buildCommands = malloc(MAX_CHARACTERS);
assert(buildCommands);
...
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
...
}
...
free(buildCommands);

How to replace a char * in C?

I am currently writing a shell for school purposes and I have the problem that if I write the command "history", the "exit" command afterwards doesn't work. If you could help me I would be very happy.
Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define MAX_INPUT 256
static char cwd[100];
void myprintf(char *text) {
text != NULL ?
printf("%s#rash:%s: %s\n", getenv("USER"), getcwd(cwd, sizeof(cwd)), text) :
printf("%s#rash:%s: ", getenv("USER"), getcwd(cwd, sizeof(cwd)));
}
void errprintf(char *text) {
myprintf(NULL);
printf("Couldn't run %s\n", text);
}
static char *argv[256];
static int argc;
static int pid = 0;
FILE *fhistory;
void parseInput(char *input) {
input = strtok(input, "\n");
for (argc = 0; argc < MAX_INPUT; argc++) {
argv[argc] = NULL;
}
argc = 0;
fprintf(fhistory, "%s\n", input);
char *param = strtok(input, " ");
while (param) {
argv[argc++] = param;
param = strtok(NULL, " ");
}
}
void signalHandler(int sign) {
switch (sign) {
case SIGINT: {
if (pid != 0) {
kill(pid, SIGKILL);
pid = 0;
}
break;
}
case SIGCHLD: {
if (pid != 0) {
kill(pid, SIGKILL);
pid = 0;
}
break;
}
}
}
int programs() {
if (!strcmp(argv[0], "exit")) {
return -1;
}
if (!strcmp(argv[0], "cd")) {
chdir(argv[1] == NULL ? getenv("HOME") : argv[1]);
} else {
pid = fork();
switch (pid) {
case -1: {
myprintf("Erectile Dysfunction!");
break;
}
case 0: {
if (!strcmp(argv[0], "history")) {
system("cat .rash_history.txt");
} else {
execvp(argv[0], argv);
errprintf(argv[0]);
}
break;
}
default: {
waitpid(pid, NULL, 0);
signal(SIGCHLD, signalHandler);
return 0;
}
}
}
return 1;
}
int main(void) {
signal(SIGINT, signalHandler);
char *input = NULL;
myprintf("Welcome to rash!");
fhistory = fopen(".rash_history.txt", "a");
while (input != NULL ? strncmp(input, "exit", strlen(input)) != 0 : 1) {
myprintf(NULL);
input = (char *) malloc(sizeof(char *) * MAX_INPUT);
int j;
for (j = 0; j < MAX_INPUT; j++) {
input[j] = '\0';
}
fgets(input, MAX_INPUT, stdin);
parseInput(input);
if (*(input) != '\n') {
programs();
}
}
fclose(fhistory);
return 0;
}
I think here while (input != NULL ? strncmp(input, "exit", strlen(input)) != 0 : 1) {
it would be strlen("exit")
The "input" variable take value inside your while loop only:
fgets(input, MAX_INPUT, stdin);
parseInput(input);
The parseInput uses strtok function couple times. The strtok modifies the argument string, so it not clear what value it will contains at time you will compare it with "exit".
Try to duplicate "input" string before calling strtok. Try to add debug string at the end of loop to make clear what value is into input string.

Resources