Advertisement
Guest User

Untitled

a guest
Dec 8th, 2019
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.00 KB | None | 0 0
  1. //
  2. // tsh - A tiny shell program with job control
  3. //
  4. // <Put your name and login ID here>
  5. //Numair Baig
  6. //
  7.  
  8. using namespace std;
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <signal.h>
  16. #include <sys/types.h>
  17. #include <sys/wait.h>
  18. #include <errno.h>
  19. #include <string>
  20.  
  21. #include "globals.h"
  22. #include "jobs.h"
  23. #include "helper-routines.h"
  24.  
  25. //
  26. // Needed global variable definitions
  27. //
  28.  
  29. static char prompt[] = "tsh> ";
  30. int verbose = 0;
  31.  
  32. //
  33. // You need to implement the functions eval, builtin_cmd, do_bgfg,
  34. // waitfg, sigchld_handler, sigstp_handler, sigint_handler
  35. //
  36. // The code below provides the "prototypes" for those functions
  37. // so that earlier code can refer to them. You need to fill in the
  38. // function bodies below.
  39. //
  40.  
  41. void eval(char *cmdline);
  42. int builtin_cmd(char **argv);
  43. void do_bgfg(char **argv);
  44. void waitfg(pid_t pid);
  45.  
  46. void sigchld_handler(int sig);
  47. void sigtstp_handler(int sig);
  48. void sigint_handler(int sig);
  49.  
  50. //
  51. // main - The shell's main routine
  52. //
  53. int main(int argc, char **argv)
  54. {
  55. int emit_prompt = 1; // emit prompt (default)
  56.  
  57. //
  58. // Redirect stderr to stdout (so that driver will get all output
  59. // on the pipe connected to stdout)
  60. //
  61. dup2(1, 2);
  62.  
  63. /* Parse the command line */
  64. char c;
  65. while ((c = getopt(argc, argv, "hvp")) != EOF) {
  66. switch (c) {
  67. case 'h': // print help message
  68. usage();
  69. break;
  70. case 'v': // emit additional diagnostic info
  71. verbose = 1;
  72. break;
  73. case 'p': // don't print a prompt
  74. emit_prompt = 0; // handy for automatic testing
  75. break;
  76. default:
  77. usage();
  78. }
  79. }
  80.  
  81. //
  82. // Install the signal handlers
  83. //
  84.  
  85. //
  86. // These are the ones you will need to implement
  87. //
  88. Signal(SIGINT, sigint_handler); // ctrl-c
  89. Signal(SIGTSTP, sigtstp_handler); // ctrl-z
  90. Signal(SIGCHLD, sigchld_handler); // Terminated or stopped child
  91.  
  92. //
  93. // This one provides a clean way to kill the shell
  94. //
  95. Signal(SIGQUIT, sigquit_handler);
  96.  
  97. //
  98. // Initialize the job list
  99. //
  100. initjobs(jobs);
  101.  
  102. //
  103. // Execute the shell's read/eval loop
  104. //
  105. for(;;) {
  106. //
  107. // Read command line
  108. //
  109. if (emit_prompt) {
  110. printf("%s", prompt);
  111. fflush(stdout);
  112. }
  113.  
  114. char cmdline[MAXLINE];
  115.  
  116. if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin)) {
  117. app_error("fgets error");
  118. }
  119. //
  120. // End of file? (did user type ctrl-d?)
  121. //
  122. if (feof(stdin)) {
  123. fflush(stdout);
  124. exit(0);
  125. }
  126.  
  127. //
  128. // Evaluate command line
  129. //
  130. eval(cmdline);
  131. fflush(stdout);
  132. fflush(stdout);
  133. }
  134.  
  135. exit(0); //control never reaches here
  136. }
  137.  
  138. /////////////////////////////////////////////////////////////////////////////
  139. //
  140. // eval - Evaluate the command line that the user has just typed in
  141. //
  142. // If the user has requested a built-in command (quit, jobs, bg or fg)
  143. // then execute it immediately. Otherwise, fork a child process and
  144. // run the job in the context of the child. If the job is running in
  145. // the foreground, wait for it to terminate and then return. Note:
  146. // each child process must have a unique process group ID so that our
  147. // background children don't receive SIGINT (SIGTSTP) from the kernel
  148. // when we type ctrl-c (ctrl-z) at the keyboard.
  149. //
  150. void eval(char *cmdline)
  151. {
  152. /* Parse command line */
  153. //
  154. // The 'argv' vector is filled in by the parseline
  155. // routine below. It provides the arguments needed
  156. // for the execve() routine, which you'll need to
  157. // use below to launch a process.
  158. //
  159. pid_t pid;//keeps track of pid
  160. char *argv[MAXARGS];
  161.  
  162. //
  163. // The 'bg' variable is TRUE if the job should run
  164. // in background mode or FALSE if it should run in FG
  165. //
  166. int bg = parseline(cmdline, argv);
  167. sigset_t mask;//block of sigchild
  168. if (argv[0] == NULL)
  169. return; /* ignore empty lines */
  170. // if(strcmp(argv[0],"quit") == 0)//if first command line argument is quit, exit the program
  171. // {
  172. // //uses strcmp to avoid pointer cmp w/ string
  173. // exit(0);//exits program
  174. // }
  175. // else if(strcmp(argv[0],"fg") == 0)//if first command line argument is foreground, run a foreground job
  176. // {
  177. // return 1;//return for proof of job
  178. // }
  179. struct job_t *job;//creates job obj ptr
  180. if(!builtin_cmd(argv))//if argv vector does not contain built in command
  181. {
  182. sigemptyset(&mask);//initializes signal stb to empty set
  183. sigaddset(&mask, SIGCHLD);//adds sigchild signal to set
  184. sigprocmask(SIG_BLOCK, &mask, NULL);//blocking until child is created
  185.  
  186. if((pid = fork()) == 0)//fork and execute
  187. {
  188. sigprocmask(SIG_UNBLOCK, &mask, NULL);
  189. setpgid(0,0);
  190. // execvp(argv[0], argv);//executes first argv with full vec vp to specify path
  191. if(execve(argv[0], argv, environ) < 0)
  192. {
  193. printf("%s: Command not found.\n", argv[0]);
  194. exit(0);//exits - terminates child
  195. }
  196. }
  197. addjob(jobs, pid, bg ? BG : FG, cmdline);//adds job
  198. sigprocmask(SIG_UNBLOCK, &mask, NULL);//to prevent queue from clogging
  199. //has job and pid
  200. //turnary op checks if background process, if not, then foreground process
  201. if(!bg)//if not background
  202. {
  203. //wait(NULL);//blocks calling process until signal is received - waits for child
  204. waitfg(pid);
  205. }
  206. else//if is background
  207. {
  208. job = getjobpid(jobs, pid); //gets job pid
  209. printf("[%d] (%d) %s/n", job->jid, pid, cmdline);//print based on desired statement from rtest
  210. //[1] (83) ./myspin 1 &
  211. }
  212. }
  213. return;
  214. }
  215.  
  216.  
  217. /////////////////////////////////////////////////////////////////////////////
  218. //
  219. // builtin_cmd - If the user has typed a built-in command then execute
  220. // it immediately. The command name would be in argv[0] and
  221. // is a C string. We've cast this to a C++ string type to simplify
  222. // string comparisons; however, the do_bgfg routine will need
  223. // to use the argv array as well to look for a job number.
  224. //
  225. int builtin_cmd(char **argv) //built in command function
  226. {
  227. string cmd(argv[0]);
  228.  
  229. if(cmd == "quit")//if first command line argument is quit
  230. {
  231. exit(0);//exits shell - performs a quit
  232. }
  233. else if(cmd == "fg")//if first command is to run a foreground process
  234. {
  235. do_bgfg(argv);//runs background foreground
  236. return 1;//returns 1 to verify process performed
  237. }
  238. else if(cmd == "bg")//if first command is to run a background process
  239. {
  240. //move process to background and quit shell
  241. do_bgfg(argv);//runs background foreground
  242. return 1;//return 1 to verify process performed
  243. }
  244. else if(cmd == "jobs")//if first command is to view jobs
  245. {
  246. listjobs(jobs);//lists the jobs
  247. return 1;//return 1 to verify process performed
  248. }
  249. return 0; /* not a builtin command */
  250. }
  251.  
  252. /////////////////////////////////////////////////////////////////////////////
  253. //
  254. // do_bgfg - Execute the builtin bg and fg commands
  255. //
  256. void do_bgfg(char **argv)
  257. {
  258. struct job_t *jobp=NULL;
  259.  
  260. /* Ignore command if no argument */
  261. if (argv[1] == NULL) {
  262. printf("%s command requires PID or %%jobid argument\n", argv[0]);
  263. return;
  264. }
  265.  
  266. /* Parse the required PID or %JID arg */
  267. if (isdigit(argv[1][0])) {
  268. pid_t pid = atoi(argv[1]);
  269. if (!(jobp = getjobpid(jobs, pid))) {
  270. printf("(%d): No such process\n", pid);
  271. return;
  272. }
  273. }
  274. else if (argv[1][0] == '%') {
  275. int jid = atoi(&argv[1][1]);
  276. if (!(jobp = getjobjid(jobs, jid))) {
  277. printf("%s: No such job\n", argv[1]);
  278. return;
  279. }
  280. }
  281. else {
  282. printf("%s: argument must be a PID or %%jobid\n", argv[0]);
  283. return;
  284. }
  285.  
  286. //
  287. // You need to complete rest. At this point,
  288. // the variable 'jobp' is the job pointer
  289. // for the job ID specified as an argument.
  290. //
  291. // Your actions will depend on the specified command
  292. // so we've converted argv[0] to a string (cmd) for
  293. // your benefit.
  294. //
  295. string cmd(argv[0]);
  296. int pid = jobp->pid;
  297. //kill with SIGCONT
  298. kill(-pid, SIGCONT);// - kills whole process group
  299. if(cmd != "fg")//check if command is foreground
  300. {
  301. jobp->state = BG;//set jobp state to background
  302. printf("[%d] (%d) %s", jobp->jid, jobp->pid, jobp->cmdline);//command of job
  303. }
  304. else
  305. {
  306. jobp->state = FG;//set jobp state
  307. waitfg(pid);
  308. }
  309.  
  310. return;
  311. }
  312.  
  313. /////////////////////////////////////////////////////////////////////////////
  314. //
  315. // waitfg - Block until process pid is no longer the foreground process
  316. //
  317. void waitfg(pid_t pid)
  318. {
  319. struct job_t *job = getjobpid(jobs, pid);//gets job using pid
  320.  
  321. if(pid != 0 && job != NULL)//to avoid seg fault
  322. {
  323. while(job->state == FG)//if job is a foreground job
  324. {
  325. sleep(1);//wait then return
  326. }
  327. }
  328. return;
  329. }
  330.  
  331. /////////////////////////////////////////////////////////////////////////////
  332. //
  333. // Signal handlers
  334. //
  335.  
  336.  
  337. /////////////////////////////////////////////////////////////////////////////
  338. //
  339. // sigchld_handler - The kernel sends a SIGCHLD to the shell whenever
  340. // a child job terminates (becomes a zombie), or stops because it
  341. // received a SIGSTOP or SIGTSTP signal. The handler reaps all
  342. // available zombie children, but doesn't wait for any other
  343. // currently running children to terminate.
  344. //
  345. void sigchld_handler(int sig)
  346. {
  347. pid_t pid;
  348. int status;
  349. //struct job_t *job;//using job struct
  350. while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)//WNOHANG doesn't wait for process
  351. {//WUNTRACED check for stop signal
  352. //job = getjobpid(jobs, pid);
  353. if(WIFSTOPPED(status))//signal not modified
  354. {
  355. getjobpid(jobs, pid)->state = ST;//set jobpid state to stop
  356. int jid = pid2jid(pid);//find pid return jid
  357. printf("Job [%d] (%d) stopped by signal %d\n", jid, pid, WSTOPSIG(status));
  358. }
  359. else if(WIFSIGNALED(status))//looks for error signal
  360. {
  361. int jid = pid2jid(pid);//gets jid from pid
  362. printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status));
  363. deletejob(jobs, pid);//deletes job after termination
  364. }
  365. else if(WIFEXITED(status))
  366. {
  367. deletejob(jobs, pid);//deletes job after termination
  368. }
  369. }
  370.  
  371. return;
  372. }
  373.  
  374. /////////////////////////////////////////////////////////////////////////////
  375. //
  376. // sigint_handler - The kernel sends a SIGINT to the shell whenver the
  377. // user types ctrl-c at the keyboard. Catch it and send it along
  378. // to the foreground job.
  379. //
  380. void sigint_handler(int sig) //passes sig int signal
  381. {
  382. int pid = fgpid(jobs);//gets pid of foreground
  383. if(pid != 0)//if not a child
  384. {//to kill child use sigchild
  385. int pass = kill(-pid, sig); //send signal to foreground
  386. //return -1 for failure
  387. if(pass < 0)
  388. {
  389. unix_error("kill error");//if attempt to kill doesn't exist
  390. }
  391. }
  392. return;
  393. }
  394.  
  395. /////////////////////////////////////////////////////////////////////////////
  396. //
  397. // sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
  398. // the user types ctrl-z at the keyboard. Catch it and suspend the
  399. // foreground job by sending it a SIGTSTP.
  400. //
  401. void sigtstp_handler(int sig) //passes sig stop signal
  402. {
  403. int pid = fgpid(jobs);//gets pid of foreground
  404. if(pid != 0)//if not a child
  405. {
  406. int pass = kill(-pid, sig); //send signal to foreground
  407.  
  408. if(pass < 0)
  409. {
  410. unix_error("kill error");
  411. }
  412. }
  413. return;
  414. }
  415.  
  416. /*********************
  417. * End signal handlers
  418. *********************/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement