Seg fault in custom C Shell

Hey all. I'm writing a C Shell for my Operating Systems class, and was hoping you could help me find an error in my code. It executes all commands properly, and accounts for piping, input/output redirection, history, and CD commands. However, whenever I use the piping feature, it will execute all the commands I put into it, but it will terminate afterwards via a segmentation fault. I can't figure out where it is coming from. I have marked the area I think it's coming from with "XXXX Starts here" and "XXXX Ends here". I feel like the getchar call is casuing the error, but I'm not sure (that bit of code was provided by my instructor). Thanks in advance for your help!

My code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>

main()
{
   char *path, *argv[20], buf[80], n, *p;
   int m, status, inword, continu;
   int inFlag, outFlag, bgFlag, k, count, j, pipes, pid, aCount, dirCount,
      hCount;
   int r_tube[2], l_tube[2];
   char *hist;
   char *h1[20] = { 0 };
   aCount = 0;
   dirCount = 0;

   while (1)
   {
      inword = 0;
      p = buf;
      m = 0;
      continu = 0;
      inFlag = outFlag = bgFlag = k = count = j = pipes = pid = 0;
      hCount = 0;
      int loc[20] = { 0 };
      char currD[50];

      printf("\nshhh> ");

      while ((n = getchar()) != '\n' || continu)   //XXXXXXXXX Starts here
      {
         if (n == ' ')
         {
            if (inword)
            {
               inword = 0;
               *p++ = 0;
            }
         }
         else if (n == '\n')
            continu = 0;
         else if (n == '\\' && !inword)
            continu = 1;
         else
         {
            if (!inword)
            {
               inword = 1;
               argv[m++] = p;
               *p++ = n;
            }
            else
               *p++ = n;
         }
      }                                    //XXXXXXXX Ends here

      *p++ = 0;
      argv[m] = 0;

      getcwd(currD, 50);

      while (argv[k] != 0)
      {                         //stores all entered commands into history array
         h1[aCount] = strdup(argv[k]);
         aCount++;
         k++;
      }
      k = 0;

      if ((strcmp(argv[0], "history") == 0) ||
         (strcmp(argv[0], "History") == 0))
      {                         //tests to see if history is asked for
         printf("History: \n");
         for (k = 0; k < aCount; k++)
            printf("%s\n", h1[k]);
      }


      if (strcmp(argv[0], "cd") == 0)
      {                         //tests to see if CD is needed
         if (strcmp(argv[1], "..") == 0)
            chdir(currD);
         else
         {
            while (argv[dirCount] != 0)
            {
               getcwd(currD, 50);
               chdir(argv[dirCount]);
               dirCount++;
            }
         }
      }

      char *outFile = NULL;
      char *inFile = NULL;
      loc[0] = 0;

      while (argv[count] != 0)
      {  //while loop sets the flags for input redirection, 
         // output redirection, background operator, and piping
         if (strcmp(argv[count], "<") == 0)
         {
            inFile = strdup(argv[count + 1]);
            argv[count] = argv[count + 1] = 0;
            inFlag = 1;
         }
         else if (strcmp(argv[count], ">") == 0)
         {
            outFile = strdup(argv[count + 1]);
            argv[count] = argv[count + 1] = 0;
            outFlag = 1;
         }
         else if (strcmp(argv[count], "&") == 0)
         {
            argv[count] = 0;
            bgFlag = 1;
         }
         else if (strcmp(argv[count], "|") == 0)
         {
            argv[count] = 0;
            loc[pipes + 1] = count + 1;
            pipes++;
            printf("LOC0: %d ", loc[0]);
            printf("LOC1: %d ", loc[1]);
            printf("LOC2: %d ", loc[2]);
            printf("DONE WITH IF\n");
         }
         else
            loc[count] = count;

         count++;
      }

      for (k = 0; k <= pipes; k++)
      {                         //actual execution of commands
         printf("IN FOR\n");
         if (k < pipes)
         {
            pipe(r_tube);
            j++;
         }

         pid = fork();          //fork child every time to exec

         if (pid > 0)
         {
            if (j > 0)
            {
               close(l_tube[0]);
               close(l_tube[1]);
            }
            l_tube[0] = r_tube[0];
            l_tube[1] = r_tube[1];
         }
         else if (pid == 0)
         {
            if ((k == 0) && (inFlag == 1))
            {
               int n = open(inFile, O_RDONLY | O_CREAT);
               if (n == -1)
               {
                  printf("Couldn't open inFile!\n");
                  exit(1);
               }
               close(0);
               dup(n);
               close(n);
            }
            else if ((k == pipes) && (outFlag == 1))
            {
               int out = open(outFile, O_WRONLY | O_CREAT, 0666);
               if (out < 0)
               {
                  printf("Could'nt open outFile!\n");
                  exit(1);
               }
               close(1);
               dup(out);
               close(out);
            }
            printf("K: %d ", k);
            printf("PIPES: %d ", pipes);
            printf("PID: %d\n", pid);
            execvp(argv[loc[k]], &argv[loc[k]]);
         }
         printf("ONE\n");
         if (bgFlag == 0)
            wait(NULL);
      }
      printf("TWO\n");
      if (strcmp(argv[0], "quit") == 0)
         exit(0);               //tests for exit/quit to end program
      if (strcmp(argv[0], "exit") == 0)
         exit(0);
      printf("THREE\n");
      for (k = 0; k < 20; k++)  //reset all of argv to NULL
         argv[k] = 0;
      printf("FOUR\n");

      wait(&status);
   }
}
Upon running, what input do you give that leads to the crash?
Does GCC compiles this code ? I think not.
It's C. gcc will compile this as C code with a few warnings.
shhh>
Program received signal SIGSEGV, Segmentation fault.
0x08048772 in main () at sh.c:56
56 *p++ = n;
(gdb) x/c 0x08048772
0x8048772 <main+318>: -120 '\210'


Hope this should help you !!!

Note error occured while executing line 56 : *p++=n;
Last edited on
@Moschops The input that leads to the error is anything to do with piping. I.e. ls -al | ls -al
Or ls | wc | more output.txt
Either of those commands will cause the seg fault.

@Modoran Yes, this code compiles perfectly fine (minus a few warnings) in a Unix/Linux environment.

@Ahmedkhan Thank you! This totally pinpoints where I believe the error to be. That segment of code was supplied by my professor, and I knew there was something wrong with it. What inputs did you use to produce that seg fault?

just use piping output of two or more linux cmds, I used "ls -l | sort" to trigger segfault
Topic archived. No new replies allowed.