Segmentation fault because of a recursive function - c

I am not very skilled in C programing. So when I'm writing this recursive function, I'm facing segmentation fault (core dumped).
int ispra(char* dir, char* proc, int num, int origin) {
FILE *newfile;
//printf("%s\n", dir);
char* s;
char* buff;
s = (char*) calloc(100, sizeof(char));
strcpy(s, dir);
strcat(s, "/");
strcat(s, proc);
strcat(s, "/status");
newfile = fopen(s, "r");
while(1) {
buff = (char*) calloc(100, sizeof(char));
int pid;
char* gran = (char*) calloc(10, sizeof(char));
int ppid;
fscanf(newfile, "%s", buff);
if (strcmp(buff, "Pid:") == 0) {
fscanf(newfile, "%d", &pid);
if (pid == num) {
return 1;
}
}
if (strcmp(buff, "PPid:") == 0) {
fscanf(newfile, "%s", gran);
ppid = atoi(gran);
if (ppid == origin) {
return 0;
}
int new = ispra(dir, gran, num, origin);
break;
}
free(buff);
}
free(s);
return -1;
}
So basically, the function reads from a given file and looks for a match with a variable num. It all works fine until I add a recursive call. Recursive call is for getting variable new.
When the recursive call is present, I get a fault and I have no idea how to make it work.

Related

Heap based char nested array

I want to pass a heap based array that contains sub arrays for arguments to a function that uses execvp, why a heap based array, because I splitting user input into a list of arguments
int split(char * str, const char * token , char *** arr)
{
int c = 1;
char * ptr = strtok(str , token);
(*arr)[0] = malloc(1024);
strcpy((*arr)[0], "-c");
while (ptr != NULL)
{
(*arr)[c] = malloc(1024);
strcpy((*arr)[c], ptr);
c++;
*arr = realloc(*arr, sizeof(char*)*(c+1));
ptr = strtok(NULL, token);
}
(*arr)[c] = NULL;
return c;
}
int run(char * args[])
{
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
return -1;
if ((pid = fork()) == -1)
return -1;
if(pid == 0){
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execvp("/bin/bash", args);
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
int main()
{
char * tmp = malloc(1024);
/* list of pointers */
char ** arr = malloc(16);
/* buffer to hold user input */
char input[1024];
scanf("%[^\n]", input);
//printf("%s\n",input);
int x = split(input, " ", &arr);
for (int i=0; i<x;i++)
{
printf("%s ",arr[i]);
}
run(arr);
char * arr2[] = {getenv("SHELL"), "-c" ,"ls","-la", NULL};
run(arr2);
}
split takes the user input and create a list of pointers where the first element is -c and the last is NULL and the user input is in the middle next it is being passed to the run function that attempts to run the command with /bin/bash but throws the error
ls -la
/usr/bin/ls: /usr/bin/ls: cannot execute binary file
-c ls -la Output: ()
where as if I where to create a stack based array of arrays then pass it to the run function everything works fine and I get the directory listings
I used getenv in the split function and then passed the whole array to run this way every thing is in the right order
int split(char * str, const char * token , char *** arr)
{
int c = 2;
char * ptr = strtok(str , token);
(*arr)[0] = malloc(1024);
/* added this as the first element in the array */
strcpy((*arr)[0], getenv("SHELL"));
(*arr)[1] = malloc(1024);
/* added this as the second element in the array */
strcpy((*arr)[1], "-c");
while (ptr != NULL)
{
(*arr)[c] = malloc(1024);
strcpy((*arr)[c], ptr);
c++;
*arr = realloc(*arr, sizeof(char*)*(c+1));
ptr = strtok(NULL, token);
}
(*arr)[c] = NULL;
return c;
}
int run(char * args[])
{
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
return -1;
if ((pid = fork()) == -1)
return -1;
if(pid == 0){
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
/* /bin/bash to args[0] */
execvp(args[0], args);
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}

Seg Fault when working with strings C Program / Popen

I have looked for an answer to my question for almost two days and tried every solution suggested to no avail.
I am trying to access a file through a linux terminal using my C Program.
I want to run popen() to do this.
The command I want to run in popen() is : grep -o %s /usr/share/dict/words
Where %s is a variable word that changes each iteration. I have tried using pointers, arrays, and alternative functions such as asprintf() / snprintf()
Here is the code I have right now:
char *message = (char *)malloc(500);
strcpy(message, "grep -n");
printf("%s", message);
strcat(message, "hello");
printf("%s", message);
strcat(message, " /usr/share/dict/words"); // SEG FAULT OCCURS HERE
printf("%s", message);
I would then pass this to popen.
I have also tried initializing as: char message[500] and this returns the same error in the same spot.
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "caeserheader.h"
int main( int argc, char *argv[]){
char *inputfile;
int n = 0;
int shiftamount = 0;
//Determine amount of arguments
if(argc == 2){
inputfile = argv[1];
}
else if(argc == 3){
inputfile = argv[1];
n = atoi(argv[2]);
shiftamount = n * (-1) ;
}
else{
printf("Please enter a proper number of arguments.");
return -1;
}
//OPENS INPUT FILE
FILE *input = fopen(inputfile, "r");
if(input == NULL){
printf("\n FILE NOT FOUND.");
perror("fopen");
return -1;
}
//RESERVES MEMORY AND GRABS STRING
fseek(input, 0L, SEEK_END);
long Tsize = ftell(input);
rewind(input);
char *inputtext;
inputtext = calloc( 1, Tsize+1);
//ERROR CHECKING
if(!inputtext){
fclose(input), printf("MEMORY FAILED.");
}
if(1!=fread( inputtext, Tsize, 1, input)){
fclose(input), free(inputtext), printf("READ FAIL.");
}
//CREATES DECRYPTED STRING
char newletter;
char *newstring;
int i;
//WITH GIVEN NUMBER OF SHIFTS
if(argc == 3){
newstring = malloc(Tsize + 1);
for(i=0; i<Tsize; i++){
newletter = shift(inputtext[i], shiftamount);
newstring[i] = newletter;
}
}
//WITHOUT GIVEN NUMBER OF SHIFTS
if(argc == 2){
char *message = (char *)malloc(500); //SEG FAULT SOMEWHERE HERE?
// strcpy(message, "grep -n");
// printf("%s", message);
//strcat(message, "hello");
// printf("%s", message);
// strcat(message, "/usr/share/dict/words");
//printf("%s", message);
// word = strtok(inputtext," ,.-!?\n");
// int i;
//for(i=0; i<10; i++){
//word = strtok(NULL," ,.-!?\n");
//printf("\n%s", word);
//}
// if(( fp = popen(message, "r")) == NULL){
//perror("No file stream found.");
//return -1;
// }
// else {
// pclose(fp);
// printf("FOUND.");
// }
}
// PUTS DECRYPTED STRING IN NEW FILE
char copiedname[100];
strcpy(copiedname, inputfile);
strcat(copiedname, ".dec");
FILE *newfile = fopen(copiedname, "w");
fputs(newstring, newfile);
// free(newstring);
fclose(input);
fclose(newfile);
return 0;
}
You have set inputfile to argv[1] and later you have used strcat to append to it. Don't do this. You don't own argv.
The strcat function appends a copy of the source string to the destination string, and then returns a pointer to the destination string. It does not "add two strings and return the result" which is how you seem to be using it.

How to get process memory on qnx

I would like to get the process memory on qnx. On a shell,I can get the result using the command showmem -P pid. In c I open a pipe for the command but then I would like to parse the output of the command but I don't know how is it done.
int main()
{
pid_t self;
FILE *fp;
char *command;
self=getpid();
sprintf(command,"showmem -P %d",self);
fp = popen(command,"r");
// Then I want to read the elements that results from this command line
}
Your idea with the popen and showmem is feasible. You just have to parse the result from the popen() in order to extract the memory information.
Here is an example, assuming you don't have shared objects:
int main(int argc, char *argv[]) {
pid_t self;
FILE *fp;
char command[30];
const int MAX_BUFFER = 2048;
char buffer[MAX_BUFFER];
char* p;
char* delims = { " ," };
int memory[] = {-1, -1, -1, -1, -1 };
int valueindex = -1;
int parserindex = 0;
self = getpid();
sprintf(command, "showmem -P %d", self);
fp = popen(command, "r");
if (fp) {
while (!feof(fp)) {
if (fgets(buffer, MAX_BUFFER, fp) != NULL) {
p = strtok( buffer, delims );
while (p != NULL) {
if (parserindex >=8 && parserindex <= 13) {
memory[++valueindex] = atoi(p);
}
p = strtok(NULL, delims);
parserindex +=1;
}
}
}
pclose(fp);
}
printf("Memory Information:\n");
printf("Total: %i\n", memory[0]);
printf("Code: %i\n", memory[1]);
printf("Data: %i\n", memory[2]);
printf("Heap: %i\n", memory[3]);
printf("Stack: %i\n", memory[4]);
printf("Other: %i\n", memory[5]);
return EXIT_SUCCESS;
}
This program generates the following output:
Memory Information:
Total: 851968
Code: 741376
Data: 24576
Heap: 73728
Stack: 12288
Other: 0

How to implement history function?

I am new to C programming and currently learning this into a course. I'm facing an issues while trying to practice the below history function.
I'm able to display the shell commands. However, when I type history, the past shell commands are not getting saved into the history buffer.
Can anyone help me to find where I went wrong?
Here is my code:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define BUFSIZE 20
#define MAX_WORD_IN_LINE 20
int tokenize(char *str, char **args)
{
int i, argc = 0;
char *token;
token = strtok(str," \t\n");
for(i=0; token!=NULL;i++)
{
args[i] = token;
printf("args[%d] = %s\n", i, args[i]);
token = strtok(NULL, " \t\n");
argc++;
}
return argc;
}
void display_strings(char **p)
{
if (p == NULL) return;
while(*p != NULL){
printf("%s\n",*p);
p++;
}
}
int history(char *hist[], int current){
int i = current;
int hist_num = 1;
do {
if (hist[i]) {
printf("%4d %s\n", hist_num, hist[i]);
hist_num++;
}
i = (i + 1) % BUFSIZE;
} while (i != current);
return 0;
}
int main(void){
char *args[MAX_WORD_IN_LINE];
char buffer[BUFSIZE];
char *hist[BUFSIZE];
int i,current=0;
pid_t pid;
int argc;
for(i=0;i<BUFSIZE;i++)
hist[i]= NULL;
while(1) {
memset(args,0,MAX_WORD_IN_LINE);
printf("osh> ");
fgets(buffer, BUFSIZE, stdin);
argc = tokenize(buffer, args);
//display_strings(args);
// skip on empty command
if (argc == 0) continue;
if (strcmp(args[0],"quit") == 0) break;
else if (strcmp(args[0], "hello") == 0) printf("Hello there. How are you?\n");
else if (strcmp(args[0],"history")==0) history(hist,current);
else {
pid = fork();
if (pid == 0) {
hist[current]=strdup(args[0]);
current++;
execvp(args[0], args);
return 0;
}
You need to make a copy of the string that args[0] points to when you save it in hist. Currently, you're just assigning the pointer to the current args[0], and it will be overwritten by the next command. When you print the history, you'll just get the last command repeatedly. So use:
hist[current] = strdup(args[0]);

c program is compiling and running but I am getting a weird output in the terminal

so I have a method that moves a string from a file to a char array in c, but when I try to print it out I am getting a weird output in the terminal that looks like a bunch of for each char spot and each box has 4 0's and 1's.
Here's the my code:
int main(int argc, char** argv){
if(argc != 3){
printf("not valid # of arguments");
return 1;
}
struct stat info;
int status;
status = stat(argv[2], &info);
if(status != 0){
printf("Error, errno = %d\n", errno);
return 1;
}
//command line argument is file
if(S_ISREG (info.st_mode)){
printf("%s is a file \n", argv[2]);
char *string1;
string1 = getFileString(argv[2]);
printf("string in file is %s \n", string1);
free(string1);
return 0;
}
if(S_ISDIR(info.st_mode)){
printf("%s is a directory \n", argv[2]);
openDirRec(argv[2]);
//what to do if command line argument is directory
}
return 0;
}
char* getFileString(char *fileName){
FILE* qp;
qp = fopen(fileName, "r");
char ch;
struct stat st;
if(stat(fileName, &st) != 0) {
return NULL;
}
/*int sizeCheck = 0;
while((ch=fgetc(qp))!=EOF){
sizeCheck++;
}
*/
int sizeCheck = st.st_size;
if(sizeCheck == 0){
return NULL;
}
else{
//fseek(qp, SEEK_SET, 0);
char *fileString;
fileString = (char*)malloc(sizeof(char) * sizeCheck + 1);
memset(fileString, 0, sizeCheck + 1);
//rewind(qp);
int count = 0;
while((ch=fgetc(qp)!=EOF)){
fileString[count] = ch;
count++;
}
printf("%s\n", fileString);
fileString[sizeCheck] = '\0';
fclose(qp);
return fileString;
}
}
This line is the culprit.
while((ch=fgetc(qp)!=EOF))
Due to operator precedence, that is equivalent to:
while(ch = (fgetc(qp)!=EOF) )
what you need is a little rearrangement of the parantheses.
while((ch=fgetc(qp)) != EOF)

Resources