1

I'm working on a program that takes the output from a script, stores it and prints the output in a certain way, more specificly either: (first name, middle/surname, key) or(middle/surname, first name, key) etc...

So I wrote the program, but I keep getting segmentation fail when I try to run it. The compilations is fine and the script works, because I tested it.

Any suggestions on what could be done different or improved?

code:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>



struct memberinfo  {
char firstname[250]; // all names except last name
char surname [100]; // surname
int  pub_key;         // 0 if the user does not have a key
};

typedef struct memberinfo acc_t;
int counter = 0;

void les_data   (acc_t *classlist);
void skriv_data (acc_t *classlist, char * select);

int main(int argc, char *argv[]) {

     acc_t classlist[200];
     char *ch = NULL;

     if(argc == 2){//checking for additional argument on execute
     ch = argv[1];//pointer becomes main argument
     }
     else if(argc < 2){//if there is less then 2 arguments
     ch = getenv("V1");//pointer gets the default environmental variable.
     }
     else{//same as above, this just makes sure that "ch" don't return with NULL value
     argc == 1;
     ch = getenv("V1");
     }

     read_data  (classlist);//calling the method for executing the script and store output
     print_data(classlist, ch);//calling the method for printing the data

     return 0;
 }


 void read_data(acc_t *classlist) {

    FILE * list;
    char *name, *fname, *lname, *tmp;
    char usertmp[1000], buffer[BUFSIZ+1];//usertmp = temporary list, buffer contain the scripts output     
    int cnt, i, chars_read;

    memset(buffer, '\0', sizeof(buffer));//memsetting buffer with all 0

    list = popen("./classlist.sh", "r");//opening and running the script in a read mode

    while(list!=NULL){ //if list is not NULL, we begin to read from it

        chars_read = fread(buffer, sizeof(char), BUFSIZ, list);//reading from scripts output,
                                                                   //storing in buffer.

        while(chars_read >0){
             //while there are still characters in file we do:



                tmp = buffer;//setting pointer to the text stored in buffer
                for(i = 0; tmp[i]!= '\n'; i++){//for-loop running until a new line is detected        
                    if(tmp[i]== ' '){ //if there is a space in text the counter increases
                            cnt++;
                    }//if end
                }//for-loop end
            name = strtok(buffer,": ");//the complete name is taken from the text in buffer        
            strcpy(usertmp, name);//the name is copied to usertmp array

            for(i = 0; i <(cnt-2); i++){//for-loop

                name = strtok(NULL, ": ");
                strcat(strcat(usertmp, " "), name); //nested strcat??
            }//for-loop end                            // saves the whole name in usertmp[]       


            name = NULL;//setting name to null, clearing the memmory
            strcpy(classlist[counter].firstname, name);//copying first name in array     

            name = strtok(NULL, ": ");//setting to NULL to skip first name
            strcpy(classlist[counter].surname, usertmp);//copy middle/last name

            name = strtok(NULL, ": ");//setting to null to skipp the middle/last name      
            classlist[counter].pub_key = atoi(name);//copy the int key to array

            counter ++;

        }//if(chars_read) end
        pclose(list);
    }//while end


}//read_data end



void print_data (acc_t *classlist, char *select) {

   switch (select[0])
   {
      case 'k':
      printf("%s %s %d\n", classlist[counter].firstname, classlist[counter].surname, 
      classlist[counter].pub_key);
       //printf("Printing out class data:\n");
         break;

      default:
      break;
    }
 }

So the script prints a group of members like this:

Script:

#! /bin/bash
grep da2001-2020 /etc/group |cut -f4 -d: > group.txt  
#Getting a list of members

tr -s ',' '\n' < group.txt |sort -k 1 -t',' -n > snm.txt 
#putting numbers in a order

sed 's/^.//' snm.txt > cnm.txt
#removing "s" in front of student number.

rm group.txt #delting group file


cut -f1,5 -d: /etc/passwd |cut -f1 -d, |sort -u > big_list.txt 
 #extracting names from file   
  
grep -f snm.txt big_list.txt   > final.txt  
#comparing the two lists

wc -l < final.txt > amount.txt
 #counting students

for id in $(cat cnm.txt); 
#scaning student numbers that were selected
do

File=$(curl -k --silent -q https://website.com/~$id/pub_key.asc| grep -o 
"BEGIN PGP PUBLIC KEY BLOCK")                                                                                                      
 #curling a request for file indicator pub_key.asc

 if [ "$File" ];
    then
            grep "$id" final.txt | cut -f2 -d: | sort > verification.txt 
             echo -e "$(cat verification.txt): 1 " #indicating has key
            #placing the students who have a key in a file with indicator
   else
          grep "$id" final.txt | cut -f2 -d: | sort > verification.txt 
            echo -e "$(cat verification.txt): 0 " #indicator no key
            #placing the students who dont have key in a file with indicator
     fi



  done 2>&1 | tee classlist.txt #exit loop, print and save output file


  rm amount.txt
  rm cnm.txt 
  rm big_list.txt
  rm snm.txt
  rm verification.txt
  rm final.txt
MCmcoy
  • 11
  • 4
  • Do you have any guess as to where in your code the segmentation occurred? – ryyker Dec 02 '20 at 14:48
  • You should use protypes for your forward functions, or put them before `main`. Also: `argc == 1;`, what are you trying to do there? – David Ranieri Dec 02 '20 at 14:49
  • Please enable/check the compiler warnings. I get 3 warnings, 2 errors. Apart from David's mention, you need to declare functions `read_data()` and `print_data()` with prototypes. – Weather Vane Dec 02 '20 at 14:51
  • ...and another warning in `read_data()` for `cnt++;` *uninitialised variable*. – Weather Vane Dec 02 '20 at 14:58
  • @Weathervane - I get a compile with warnings, no errors. but this is unix specific, as I think a `.sh` is the extension for a Bourne shell script. – ryyker Dec 02 '20 at 15:06
  • What OS it this written for, UNIX/Linux? – ryyker Dec 02 '20 at 15:06
  • 1
    @ryyker the errors were for the two functions without protoypes. First each has a warning, and when the function itself is compiled, the error comes from a non-matching definition (contradicts the compiler's earlier assumption). MSVC : I get errors for `popen()` and `pclose()` too, but that's to be expected. – Weather Vane Dec 02 '20 at 15:08
  • Link `classlist.sh`, or if it is short, paste its contents into the edit box. – ryyker Dec 02 '20 at 15:11
  • @ryyker, it's got 55 members, so I'll se if there's place enough. – MCmcoy Dec 02 '20 at 15:15
  • Edit the script so that it contains just what is necessary to allow it to run. i.e. can you reduce it to just 2 or 3 members? (if you have not previously done so, please read this: [mcve]) – ryyker Dec 02 '20 at 15:21
  • I cant really reduce it, since its getting information from other files and combinding them. Besides, Im not sure how to link the script from a remote server to here (Im new at StackOverflow), sorry. – MCmcoy Dec 02 '20 at 15:41
  • @ryyker, it's written for Linux yes, more specific Debbian. – MCmcoy Dec 02 '20 at 15:43
  • That shell script is a heavy metal festival of antipatterns. Try http://shellcheck.net/ – tripleee Dec 02 '20 at 16:30
  • Well, I am completely new to both c programing and scripts, so, tried my best :D But thanks for the advice/link. – MCmcoy Dec 02 '20 at 17:00

1 Answers1

1

I can help you walk through how to debug this kind of thing,

When you run the program, you get a segmentation fault like this right?

Segmentation fault (core dumped)

These are tricky to debug, since it doesn't give you much to work with. But you should be left with a file called core in the same folder as your executable.

The core file is super useful for tracking down Segmentation faults, and other people have explained how to use it better than I can: Core dump file analysis


If you follow all those steps, you should be able to find the line of the program that caused the crash:

#1  0x0000000000400ab9 in read_data (classlist=0x7ffd308e82a0) at test.c:82
82              strcpy(classlist[counter].firstname, name);//copying first name in array    

And from there, you know that this line caused the crash.

From there, its a problem with strcpy usage. It caused the crash because name is set to NULL, and strcpy expects that its arguments point to a buffer, and neither are NULL.

GandhiGandhi
  • 1,029
  • 6
  • 10
  • Thank you! I couldn't find the "core file" even with "ls -a" But is this method possible to use with dgb? Also, I have some trouble understanding, how I would be able to parse through a name without "reset" the name pointer.. But I'll give it a try and read some more. Thanks again. – MCmcoy Dec 02 '20 at 15:38
  • For `strcpy` usage, `strcpy(dest, src)` copies the string stored in `src` to memory pointed to by `dest`. If ``src` is `NULL`, then the function will try to dereference a null pointer which is illegal. Also - my answer had assumed you're on Linux. I think the answer is different if you're on Windows or Mac. If no `core` file is present then there is a distribution-specific configuration change to make to enable core dumps. Just curious, what is `dgb`? I can't find any info on it :) – GandhiGandhi Dec 02 '20 at 16:06
  • My fault there, I ment gdb, the default debugger. I get the strcpy part, but my problem is that I need to save both the first name and last name in same array, without strtok destroying the string. So you mean I dont need to drain the memory and just let the "name" start strcpy from whereever it is? And yes, Im on linux (debbian). But does it have anything to do if I'm remote connected to the server via vscode on a bash terminal? I thought that should be just fine :/ – MCmcoy Dec 02 '20 at 16:12
  • Gotchya. 1) I think `ulimit -c unlimited` will enable core dumps for Debian, then 2) give that link a read, it has instructions for debugging core dumps with `gdb`. I think you're not on the right page yet with `strtok` and `strcpy` functions. I'm not going to answer here, but I'd recommend printing out `tmp`, `name` and `usertmp` variables with `printf()` before and after every time those variables change might better illustrate how those functions work. – GandhiGandhi Dec 02 '20 at 16:49
  • 1
    That's a great tip! I usually do that aswel, but yeah ill print out and see what happends :) Thanks, I just started coding 3 months ago, so im still kinda new at this. A lot to read up on, and try and fails. – MCmcoy Dec 02 '20 at 17:04
  • "try and fails" - 10 years later and I'm still doing the same every day and love it. Good luck on your journey! – GandhiGandhi Dec 02 '20 at 19:49