forked from liuhaotian/tsh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtsh.c
209 lines (181 loc) · 5.49 KB
/
tsh.c
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
206
207
208
209
/***************************************************************************
* Title: tsh
* -------------------------------------------------------------------------
* Purpose: A simple shell implementation
* Author: Stefan Birrer
* Version: $Revision: 1.4 $
* Last Modification: $Date: 2009/10/12 20:50:12 $
* File: $RCSfile: tsh.c,v $
* Copyright: (C) 2002 by Stefan Birrer
***************************************************************************/
#define __MYSS_IMPL__
#define _GNU_SOURCE
/************System include***********************************************/
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
/************Private include**********************************************/
#include "tsh.h"
#include "io.h"
#include "interpreter.h"
#include "runtime.h"
/************Defines and Typedefs*****************************************/
/* #defines and typedefs should have their names in all caps.
* Global variables begin with g. Global constants with k. Local
* variables should be in all lower case. When initializing
* structures and arrays, line everything up in neat columns.
*/
#define BUFSIZE 80
/************Global Variables*********************************************/
char** paths;
char* filedir;
char* currentdir;
char* cmdLine;
pid_t fgpid; // pid of fg
//pid_t lspid; // pid of last stopped
char* fgcommands; // remember foreground's commands
bgjobL* bgjobs;
bgjobL* donejobs;
int fgstatus; // status for busy while loop of foreground
/************Function Prototypes******************************************/
/* handles SIGINT and SIGSTOP signals */
static void sig(int);
/************External Declaration*****************************************/
/**************Implementation***********************************************/
/*
* main
*
* arguments:
* int argc: the number of arguments provided on the command line
* char *argv[]: array of strings provided on the command line
*
* returns: int: 0 = OK, else error
*
* This sets up signal handling and implements the main loop of tsh.
*/
int
main(int argc, char *argv[])
{
/* Initialize command buffer */
cmdLine = malloc(sizeof(char*) * BUFSIZE);
/* shell initialization */
if (signal(SIGINT, sig) == SIG_ERR)
PrintPError("SIGINT");
if (signal(SIGTSTP, sig) == SIG_ERR)
PrintPError("SIGTSTP");
if (signal(SIGCHLD, sig) == SIG_ERR)
PrintPError("SIGCHLD");
// Initialize global vars
paths = (char**)malloc(100*sizeof(char*));
filedir = (char*)malloc(500*sizeof(char));
currentdir = (char*)malloc(500*sizeof(char));
fgcommands = (char*)malloc(500*sizeof(char));
char pathsWithTokens[1024];
strcpy(pathsWithTokens, getenv("PATH"));
// Using strtok to parse : out of pathsWithTokens and put each directory string into paths
int i = 0;
char* temp = strtok(pathsWithTokens, ":");
if (temp)
{
do
{
paths[i] = temp;
i++;
}
while ((temp = strtok(NULL, ":")) != NULL);
}
while (TRUE) /* repeat forever */
{
// Update currentdir
char *getCwdReturn = getcwd(currentdir, 500*sizeof(char));
if (getCwdReturn == NULL)
PrintPError("Error in finding current working directory");
/* read command line */
getCommandLine(&cmdLine, BUFSIZE);
if (strcmp(cmdLine, "exit") == 0)
break;
fgpid = 0;
/* checks the status of background jobs */
CheckJobs();
/* interpret command and line
* includes executing of commands */
Interpret(cmdLine);
fflush(stdout);
fgpid = 0;
//fgpid = (pid_t *)NULL;
}
/* shell termination */
free(cmdLine);
free(paths);
free(filedir);
free(currentdir);
free(fgcommands);
return 0;
} /* main */
/*
* sig
*
* arguments:
* int signo: the signal being sent
*
* returns: none
*
* This should handle signals sent to tsh.
*/
static void
sig(int signo)
{
if (signo == SIGINT) // Handle SIGINT
{
if (fgpid)
kill(-fgpid, SIGINT);
}
if (signo == SIGTSTP) // Handle SIGTSTP
{
if (fgpid != 0)
{
//lspid = fgpid;
int index;
if (getmostrecentjob() == NULL) // no one in jobs list
index = 1;
else
index = findindexpid( (getmostrecentjob())->pid ) + 1;
printf("[%d] Stopped %s\n", index, fgcommands);
fflush(stdout);
//if (fgcommands[strlen(fgcommands)-1] != '&')
//strcat(fgcommands, " &");
int i = addjob(fgpid, _STOPPED, fgcommands, _JOBLIST); // foreground becomes background
kill(-fgpid, SIGTSTP);
if (i == 0)
PrintPError("Error adding job");
}
}
if (signo == SIGCHLD) // Handle SIGCHLD
{
pid_t chldpid;
int status;
chldpid = waitpid(-1, &status, WUNTRACED | WNOHANG); // wait on child with options for stopping childs
if (chldpid == fgpid) // the foreground sent a SIGCHLD
{
fgstatus = _STOPPED; // set fgstatus to 0 so that the sleep loop in Exec can exit
}
else if (WIFEXITED(status) || WIFSIGNALED(status)) // SIGCHLD from bg process
{
if ( findjobpid(chldpid) == NULL) // not in list
return;
int index = findindexpid(chldpid);
if (WIFSIGNALED(status)) // bg child terminated with error status, notify user
{
printf("[%d] terminated with status %d PID: %d\n", index, WTERMSIG(status), chldpid);
fflush(stdout);
}
if ( !removejob( findjobpid( chldpid ), _JOBLIST, 0 ) ) //Find job in list and remove it
PrintPError("SIGCHLD from child that is not a job");
}
}
} /* sig */