CSV Parsing and Insert to Database - Null Values and Segmentation Fault - c

Im using the following code to parse a CSV and insert the values into a table
void readcsv()
{
FILE* stream = fopen("input.csv", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
char a1[20]= "";
char b1[20]= "";
char c1[20]= "";
char d1[20]= "";
char e1[20]= "";
char f1[20]= "";
strcat(a1, getcsvfield(tmp, 1));
strcat(b1, getcsvfield(tmp, 2));
strcat(c1, getcsvfield(tmp, 3));
strcat(d1, getcsvfield(tmp, 4));
strcat(e1, getcsvfield(tmp, 5));
strcat(f1, getcsvfield(tmp, 6));
strcat(a1, '\0');
strcat(b1, '\0');
strcat(c1, '\0');
strcat(d1, '\0');
strcat(e1, '\0');
strcat(f1, '\0');
// printf("Field 1 would be %s\n", a1);
// printf("Field 2 would be %s\n", getcsvfield(tmp, 2));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 3));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 4));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 5));
// printf("Field 2 would be %s\n", getcsvfield(tmp, 6));
//--- // execute("INSERT INTO sdata(sid,name,area,type,stbamount,pkgamount) VALUES('%s','%s','%s','%s','%s','%s');",a1,b1,c1,d1,e1,f1);
// NOTE strtok clobbers tmp
free(tmp);
}
}
//Used for parsing CSV
const char* getcsvfield(char* line, int num)
{
char buffer[1024]= {0};
strcpy(buffer, line);
const char* tok;
for (tok = strtok(buffer, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
This is the CSV
me;val1;val2;val3;val4;val5;
me;val1;val2;val3;val4;val5;
ERROR:
Segmentation fault (core dumped)
UPDATE:
database.c
#include "../include/header.h"
int Open_Database()
{
int rc=0;
rc = Initialize_db();
if(rc == 0)
{
printf("\nFailed to initialize db");
return FAILED;
}
printf("\n Database initialization success");
rc = open_sqlite("/mnt/jffs2/db2.db");
if(rc == 0)
{
printf("\n Failed to open db");
return FAILED;
}
else
printf("Database already exists\n");
printf("\n database opened\n");
return SUCCESS;
}
int Initialize_db()
{
char *database = "/mnt/jffs2/db2.db";
int rc=0, i=0;
struct stat buf;
i = stat(database, &buf );
if((i<0) || (buf.st_size == 0))
{
printf("Initializing database...\n");
lk_dispclr();
lk_disptext(2,0,(unsigned char *)" Initializing DB...",0);
rc = open_sqlite(database);
if(rc == 0)
{
printf("Create database failure!\n");
lk_dispclr();
//DispText(2,0," Failed to Create",0);
//DispText(4,4," Database",0);
lk_getkey();
return FAILED;
}
else
{
rc = execute("CREATE TABLE if not exists sdata(sid VARCHAR(10),name VARCHAR(20),area VARCHAR(10),type VARCHAR(10),stbamount VARCHAR(10),pkgamount VARCHAR(10))");
if(rc==0)
{
return error_handler(rc);
}
else
{
printf("\n Master table created\n");
}
rc = execute("CREATE TABLE if not exists tdata(sid VARCHAR(10),stbamount VARCHAR(10),pkgamount VARCHAR(10))");
if(rc==0)
{
return error_handler(rc);
}
else
{
printf("\n Transaction table created\n");
}
}
close_sqlite();
}
else
{
printf("database already existed\n");
rc=1;
}
return rc;
}
int error_handler(int rc)
{
if(rc == 0)
{
printf("\n SQL Error while initializing!!!\n");
/*lk_dispclr();
DispText(2,0," SQL ERROR",0);
lk_getkey();
*/
return FAILED;
}
else
{
printf("SQL Successfull\n");
/*lk_dispclr();
DispText(2,0," SQL Successfull",0);
lk_getkey();*/
}
return SUCCESS;
}
//-----------------------------------------------------------------------
e_sqlite.c
#include "../include/sqlite3.h"
#include "../include/header.h"
#define ELEMENT_NUM(_array) ( sizeof(_array)/sizeof(_array[0]) )
sqlite3 *db_conn;
int ret = 0;
char OPEN_FLAG = 0;
int open_sqlite(char *db_name)
{
if(OPEN_FLAG == 0)
{
if(sqlite3_open(db_name, &db_conn) == SQLITE_OK)
{
OPEN_FLAG = 1;
printf("\nOPEN_FALG = %d\n",OPEN_FLAG);
printf("database opened\n");
return 1;
}
else
{
printf("database opening failed\n");
return 0;
}
}
else
{
printf("\ndatabase already opened\n");
return 1;
}
return 1;
}
int close_sqlite()
{
if(OPEN_FLAG == 1)
{
if(sqlite3_close(db_conn) == SQLITE_OK)
{
printf("database closed\n");
OPEN_FLAG = 0;
printf("OPEN_FLAG = %d\n",OPEN_FLAG);
return 1;
}
else
{
printf("database closing failed\n");
return 0;
}
}
else
{
printf("database not yet opened\n");
return 1;
}
}
//only type s and d are allowed as arguments
int execute(const char* fmt, ...)
{
char *err_messg;
int ret=0, result = 0;
char sql_string[2000]="";//this honestly needs to be more elegant; will do for now
//char sql_string[1024]="";//this honestly needs to be more elegant; will do for now
va_list args;
va_start(args, fmt);
SQLITE = 1;
memset(sql_string,0,sizeof(sql_string));
sql_string[0] = '\0';
ret = vsprintf(sql_string, fmt, args);
va_end(args);
err_printf(sql_string);//
if(!ret)
result = 0;
else
result = 1;
if(result != -1)
{
if(sqlite3_exec(db_conn, sql_string, NULL, 0, &err_messg) == SQLITE_OK)
{
result = 1;
}
else
{
fprintf(stdout,"SQL error: %s\n", err_messg);
result = 0;
}
}
SQLITE = 0;
return result;
}
//you must open_sqlite first before using execute_file
int execute_file(char *filename)
{
char *err_messg;
FILE *read_fd = (FILE *) 0;
char sql_string[1024];
ret = 0;
read_fd = fopen (filename, "r");//open file for read
if (read_fd != NULL)
{
rewind(read_fd);
while(!feof (read_fd))
{
m_fgets(sql_string, 1024, read_fd);
//ie if string is not empty, then execute - ha no more newline errors!
if(strcmp(sql_string, "") != 0)
{
//err_printf("SQL_STRING: %s\n", sql_string);
if(sqlite3_exec(db_conn, sql_string, NULL, 0, &err_messg) == SQLITE_OK)
{
ret = 1;
continue;
}
else
{
fprintf(stdout,"SQL error: %s\n", err_messg);
ret = 0;
break;
}
}
}
}
fclose(read_fd);
return ret;
}
char *m_fgets(char *line, int n, FILE *fd)
{
int c = 0;
char *cstring;
cstring = line;
while(--n>0 && ( c = getc(fd) ) != EOF)
{
if (c == '\n')
break;
*cstring++ = c;
}
*cstring++ = '\0';
if (c == EOF && cstring == line)//ie nothing in file!
line = NULL;
if (c == EOF)
line = NULL;
return line;
}
resultset get_result(const char* fmt, ...)
{
int success = 0;
int nrow=0, ncol=0, i=0, j=0, count=0;
char *err_messg;
char **result;
char ***recordset;
resultset resultset_table;
char sql_string[1500];//this honestly needs to be more elegant; will do for now
va_list args;
va_start(args, fmt);
sql_string[0] = '\0';
ret = vsprintf(sql_string, fmt, args);
va_end(args);
fprintf(stdout,"\n%s\n", sql_string);
SQLITE = 1;
//initialize resultset_table;
resultset_table.rows = 0;
resultset_table.cols = 0;
resultset_table.recordset = NULL;
ret = sqlite3_get_table(
db_conn,
sql_string,
&result,
&nrow,
&ncol,
&err_messg
);
fprintf(stdout,"nrow=%d ncol=%d\n",nrow,ncol);
recordset = (char ***)malloc(nrow * sizeof(char **));
for(count=ncol; count<((nrow + 1)*ncol); count++)
{
recordset[i] = (char **)malloc(ncol * sizeof(char *));
for(j=0; j<ncol; j++)
{
err_printf("%s ",result[count]);//
recordset[i][j] = (char *) malloc( (strlen(result[count]) + 1) );
strcpy(recordset[i][j], result[count]);
if(j != (ncol - 1))
count++;
}
i++;
err_printf("\n");//
}
sqlite3_free_table(result);
if( ret != SQLITE_OK )
{
fprintf(stdout,"SQL error: %s\n", err_messg);
success = 0;
}
else
{
resultset_table.rows = nrow;
resultset_table.cols = ncol;
resultset_table.recordset = recordset;
success = 1;
}
SQLITE = 0;
return resultset_table;
}
//will free all allocd memory ie only recordset memory (since only that allocd)
void free_result(resultset resultset_table)
{
int i=0,j=0;
if(resultset_table.recordset != NULL)
{
for(i=0;i<resultset_table.rows;i++)
{
for(j=0;j<resultset_table.cols;j++)
{
free(resultset_table.recordset[i][j]);
}
free(resultset_table.recordset[i]);
}
free(resultset_table.recordset);
}
}
//if DEBUG is on then print message to stderr using fprintf function
/*int err_printf(const char *fmt, ...)
{
int i;
va_list ap;
va_start(ap, fmt);
i = vfprintf(stderr, fmt, ap);
va_end(ap);
return i;
}*/
//returns the row index in the resultset that was selected
//column is the column of the resultset that you want to display
int err_printf(const char *fmt, ...)
{
int i;
// #ifdef DEBUG
va_list ap;
va_start(ap, fmt);
i = vfprintf(stderr, fmt, ap);
va_end(ap);
// #endif
return i;
}
Update:
Fix for Null Values:

Related

Why gdb showed /stdlib/strtol_l.c: No such file or directory? Do I missing something to install?

I tried to compile with -g and then run gdb to find the line that caused the segmentation fault, but the error message confused me.
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0, loc=0x7ffff7fb04a0 <_nl_global_locale>)
at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: No such file or directory.
I tried reinstalling gdb to get it working again, but I failed. It still shows the same error message. I later found the problem myself and marked it in the code below. I'm just curious why something like this sometimes happens when I try to debug some string functions? Like strdup, strtok, strtol, etc.. Am I missing something to install? I hope I can solve this problem completely.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char buff[255];
#define NUM_BUCKETS 32
typedef struct Customer {
char* email;
char* name;
int shoesize;
char* food;
struct Customer* next;
} Customer ;
unsigned long hash(char *str) {
unsigned long hash = 0;
int c;
while (*str != '\0') {
c = *str;
hash = ((hash << 5) + hash) + (unsigned char)c;
str++;
}
return hash;
}
Customer *add_friend_to_list(char *email, char *name, int shoesize, char *food, Customer *bucket) {
Customer* customer;
customer = malloc(sizeof(Customer));
customer->name = strdup(name);
customer->food = strdup(food);
customer->shoesize = shoesize;
customer->email = strdup(email);
customer->next = bucket;
return customer;
}
void add_consumer_to_hashtable(char *name, char *food, char *email, int shoesize, Customer **buckets, size_t num_buckets) {
size_t which_bucket = hash(name) % num_buckets;
buckets[which_bucket] = add_friend_to_list(email, name, shoesize, food, buckets[which_bucket]);
}
int main() {
Customer* buckets[NUM_BUCKETS] = {NULL};
int ittime = 0;
FILE *fp = NULL;
fp = fopen("customers.tsv", "r");
while (true) {
fgets(buff, 255, fp);
if (feof(fp)) {
break;
}
ittime++;
}
fclose(fp);
fp = NULL;
char *email = (char *)malloc(5 * sizeof(char));
char *name = (char *)malloc(5 * sizeof(char));
int shoesize;
char *food = (char *)malloc(5 * sizeof(char));
const char s[2] = "\t";
fp = fopen("customers.tsv", "r");
for (int i = 0; i < ittime + 1; i++) { //This line cause the Segmentation Fault
fgets(buff, 255, fp);
char *token;
token = strtok(buff, s);
email = token;
token = strtok(NULL, s);
name = token;
token = strtok(NULL, s);
shoesize = atoi(token);
token = strtok(NULL, s);
food = token;
add_consumer_to_hashtable(name, food, email, shoesize, buckets, NUM_BUCKETS);
}
fclose(fp);
while (true) {
char *cmd = (char *)malloc(5 * sizeof(char));
printf("command: ");
scanf("%s", cmd);
if (strcmp(cmd, "add") == 0) {
char *email1 = (char *)malloc(5 * sizeof(char));
char *name1 = (char *)malloc(5 * sizeof(char));
int shoesize1;
char *food1 = (char *)malloc(5 * sizeof(char));
printf("email address? ");
scanf("%s", email1);
printf("name? ");
scanf(" %[^\n]", name1);
printf("shoe size? ");
scanf("%d", &shoesize1);
printf("favorite food? ");
scanf("%s", food1);
add_consumer_to_hashtable(name1, food1, email1, shoesize1, buckets, NUM_BUCKETS);
free(name1);
free(food1);
free(email1);
} else if (strcmp(cmd, "lookup") == 0) {
char *Email = (char *)malloc(5 * sizeof(char));
printf("email address? ");
scanf("%s", Email);
bool exist = false;
for (int i = 0; i < 32; i++) {
Customer *cus = buckets[i];
if (buckets[i] == NULL) {
continue;
}
while ((cus != NULL)) {
if (cus->shoesize == EOF) {
break;
}
if (strcmp(cus->email, Email) == 0) {
printf("email: %s\n", cus->email);
printf("name: %s\n", cus->name);
printf("shoesize: %d\n", cus->shoesize);
printf("food: %s\n", cus->food);
exist = true;
break;
}
if (cus->next != NULL) {
cus = cus->next;
} else {
break;
}
}
}
if (exist == false) {
printf("user not found!\n");
}
} else if (strcmp(cmd, "delete") == 0) {
char *Email = (char *)malloc(5 * sizeof(char));
printf("email address? ");
scanf("%s", Email);
bool exist = false;
for (int i = 0; i < 32; i++) {
Customer *cus = buckets[i];
if (buckets[i] == NULL) {
continue;
}
while ((cus != NULL)) {
if (cus->shoesize == EOF) {
break;
}
if (strcmp(cus->email, Email) == 0) {
free(cus->email);
free(cus->food);
free(cus->name);
free(cus);
cus->shoesize = EOF;
cus = NULL;
exist = true;
break;
}
if (cus->next != NULL) {
cus = cus->next;
} else {
break;
}
}
}
if (exist == false) {
printf("user not found!\n");
}
} else if (strcmp(cmd, "list") == 0) {
for (int i = 0; i < 32; i++) {
Customer *cus = buckets[i];
if (buckets[i] == NULL) {
continue;
}
while ((cus != NULL) && ((cus->shoesize) != EOF)) {
printf("email: %s\n", cus->email);
printf("name: %s\n", cus->name);
printf("shoesize: %d\n", cus->shoesize);
printf("food: %s\n", cus->food);
if (cus->next != NULL) {
cus = cus->next;
printf("\n");
} else {
break;
}
}
}
} else if (strcmp(cmd, "quit") == 0) {
break;
} else if (strcmp(cmd, "save") == 0) {
fp = fopen("customers.tsv", "w");
for (int i = 0; i < 32; i++) {
Customer *cus = buckets[i];
if (buckets[i] == NULL) {
continue;
}
while ((cus != NULL) && ((cus->shoesize) != EOF)) {
fprintf(fp, "%s\t%s\t%d\t%s", cus->email, cus->name, cus->shoesize, cus->food);
if (cus->next != NULL) {
cus = cus->next;
fprintf(fp, "\n");
} else {
break;
}
}
}
fclose(fp);
} else {
printf("unknown command\n");
}
}
for (int i = 0; i < 32; i++) {
Customer *tmp;
Customer *cus = buckets[i];
if (cus == NULL) {
continue;
}
if (cus->next != NULL) {
tmp = cus;
cus = cus->next;
} else {
break;
}
while ((tmp != NULL)) {
if (tmp->shoesize != EOF) {
free(tmp->email);
free(tmp->food);
free(tmp->name);
free(tmp);
}
cus->shoesize = EOF;
cus = NULL;
}
if (tmp != NULL) {
free(tmp);
}
if (cus != NULL) {
free(cus);
}
}
return 0;
}
I tried to compile with -g and then run gdb to find the line that caused the segmentation fault, but the error message confused me.
The error message means:
crash happened inside GLIBC strtol_l_internal() function
GDB can't show you the source of that function because libc6-src (or similar) package is not installed.
Now, looking at the source for strtol_l_internal() is not going to be helpful -- the root cause of the problem is that you called it with incorrect parameter.
You should read man strtol and verify that you satisfied its preconditions.
It looks like you called strtol(NULL, NULL, ...), which is not a valid thing to do. You could use (gdb) up command to find out where the wrong call came from, and fix the caller.

exec failed with fork() and execvp()

I am currently working on a program in which I have to write a shell in C. I am having trouble getting the fork() section of my program to work. Here is my code:
void execute_func(char** tok)
{
pid_t pid = fork();
if (pid == -1)
{
printf("\nERROR: forking child process failed\n");
return;
}
else if (pid == 0)
{
if (execvp(tok[0], tok) < 0)
{
printf("ERROR: exec failed\n");
}
exit(0);
}
else
{
wait(NULL);
return;
}
}
for example, if I am to type in any sort of function such as "ls" or "wc" it gives me the "ERROR: exec failed" message, which means that the fork() is not running correctly. This could be a small issue in my understanding of fork() but I am completely stumped.
here is my whole program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
char str[129];
enum {NOT_FOUND=0,FOUND};
enum {false=0,true};
static char *ptr;
const char *del;
int ReadLine(char *, int , FILE *);
char *mystrtok(char* string,const char *delim)
{
int j,flag=NOT_FOUND;
char *p;
if(string != NULL)
{
ptr=string;
p=string;
}
else
{
if(*ptr == '\0')
return NULL;
p=ptr;
}
while(*ptr != '\0')
{
del=delim;
while(*del != '\0')
{
if(*ptr == *del)
{
if(ptr == p)
{
p++;
ptr++;
}
else
{
*ptr='\0';
ptr++;
return p;
}
}
else
{
del++;
}
}
ptr++;
}
return p;
}
void execute_func(char** tok)
{
pid_t pid = fork();
if (pid == -1)
{
printf("\nERROR: forking child process failed\n");
return;
}
else if (pid == 0)
{
if (execvp(tok[0], tok) < 0)
{
printf("ERROR: exec failed\n");
}
exit(0);
}
else
{
wait(NULL);
return;
}
}
int main()
{
int i;
char *p_str,*token;
char delim[10];
delim[0] = ' ';
delim[1] = '\t';
delim[2] = '\n';
delim[3] = '\0';
char cwd[1024];
char *tok[129];
while(1)
{
tok[0] = NULL;
fflush(stdin);
fflush(stdout);
printf("\n Enter a string to tokenize: ");
// printf("\n before scan");
fflush(stdin);
// printf("\n fflush");
ReadLine(str, 128, stdin);
/* scanf("%[^\n]",str); */
printf("\n after scan");
for (i = 1, p_str = str; ; i++, p_str = NULL)
{
token = mystrtok(p_str,delim);
if (token == NULL)
break;
printf("%d: %s\n",i,token);
tok[i-1] = token;
printf("%s\n",tok[i-1]);
}
if(tok[0] != NULL)
{
if(strcmp(tok[0],"cd") == 0)
{
if (chdir(tok[1]) != 0)
perror("chdir() error()");
getcwd(cwd, sizeof(cwd));
printf("current working directory is: %s\n", cwd);
}
else if(strcmp(tok[0],"pwd") == 0)
if (getcwd(cwd, sizeof(cwd)) == NULL)
perror("getcwd() error");
else
printf("current working directory is: %s\n", cwd);
else if(strcmp(tok[0],"exit") == 0)
exit(3);
else
{
execute_func(tok);
}
}
}
}
int ReadLine(char *buff, int size, FILE *fp)
{
buff[0] = '\0';
buff[size - 1] = '\0'; /* mark end of buffer */
char *tmp;
if (fgets(buff, size, fp) == NULL)
{
*buff = '\0'; /* EOF */
return false;
}
else
{
/* remove newline */
if ((tmp = strrchr(buff, '\n')) != NULL)
{
*tmp = '\0';
}
}
return true;
}
Problem appears to be here:
if (token == NULL)
break;
printf("%d: %s\n",i,token);
tok[i-1] = token;
The trailing NULL never gets set in tok thus resulting in execve not finding the end of the list. Like this should fix it:
tok[i-1] = token;
if (token == NULL)
break;
printf("%d: %s\n",i,token);

How to Parse an AT command response and one among the fields from the output in C

Im trying to capture the data from the AT command response but im unable to do so.
My Approach.
functions():
#define MAX_LINE_LENGTH (8 * 1024)
static char buf[MAX_LINE_LENGTH];
static char buf2[MAX_LINE_LENGTH];
static bool tr_lf_cr(const char *s)
{
char *p;
p = strchr(s, '\n');
if (p == NULL || p[1] != '\0') {
return false;
}
*p = '\r';
return true;
}
static void strip_cr(char *s)
{
char *from, *to;
from = to = s;
while (*from != '\0') {
if (*from == '\r') {
from++;
continue;
}
*to++ = *from++;
}
*to = '\0';
}
#define STARTS_WITH(a, b) ( strncmp((a), (b), strlen(b)) == 0)
main()
fd = fopen(*mp, "r+b");
if (fd == NULL) {
/* Could not open the port. */
perror("open_port: Unable to open /dev/ttyUSB0\n");
}
char str = '\n';
strncat(cmd, &str, 1);
success = tr_lf_cr(cmd);
if (! success) {
fprintf(stderr, "invalid string: '%s'\n", cmd);
return EXIT_FAILURE;
}
int res = fputs(cmd, fd);
if (res < 0) {
fprintf(stderr, "failed to send '%s' to modem (res = %d)\n", cmd, res);
return EXIT_FAILURE;
}
do {
line = fgets(buf, (int)sizeof(buf), fd);
if (line == NULL) {
fprintf(stderr, "EOF from modem\n");
return EXIT_FAILURE;
}
strcpy(buf2, line);
strip_cr(buf2);
char delim[] = ",";
char *ptr = strtok(buf2, delim);
printf("\n0++++++++++++++++++++\n");
while (ptr != NULL) {
printf("'%s'\n", ptr);
ptr = strtok(NULL, delim);
}
printf("\n1********************\n");
} while (STARTS_WITH(line, "OK") == 0);
I get the following output when i run this command AT^HCSQ?
0++++++++++++++++++++
'AT^HCSQ?
'
0++++++++++++++++++++
'^HCSQ: "WCDMA"'
'64'
'64'
'60'
'0
'
0++++++++++++++++++++
'
'
0++++++++++++++++++++
'OK
'
What i want to achieve is to store each value separately from the buffer like
char p = WCDMA;
int rssi = atoi[ptr];
[etc...]
Im using strtok() to achieve this but im unable to skip the empty lines i get from the response. What should i do here?

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);

Resources