Guest User

Untitled

a guest
Oct 28th, 2016
1,095
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.70 KB | None | 0 0
  1.  
  2. /*
  3. * tsh - A tiny shell program with job control
  4. * <The line above is not a sufficient documentation.
  5. * You will need to write your program documentation.
  6. * Follow the 15-213/18-213/15-513 style guide at
  7. * http://www.cs.cmu.edu/~213/codeStyle.html.>
  8. *
  9. * @Date October 24 2016
  10. * @Author Sachin Menezes <smenezes>
  11. */
  12.  
  13. #include <sys/wait.h>
  14. #include "tsh_helper.h"
  15. #include "csapp.h"
  16.  
  17. /*
  18. * If DEBUG is defined, enable contracts and printing on dbg_printf.
  19. */
  20. #ifdef DEBUG
  21. /* When debugging is enabled, these form aliases to useful functions */
  22. #define dbg_printf(...) printf(__VA_ARGS__)
  23. #define dbg_requires(...) assert(__VA_ARGS__)
  24. #define dbg_assert(...) assert(__VA_ARGS__)
  25. #define dbg_ensures(...) assert(__VA_ARGS__)
  26. #else
  27. /* When debugging is disabled, no code gets generated for these */
  28. #define dbg_printf(...)
  29. #define dbg_requires(...)
  30. #define dbg_assert(...)
  31. #define dbg_ensures(...)
  32. #endif
  33.  
  34. volatile sig_atomic_t flag;
  35.  
  36. /* Function prototypes */
  37. void eval(const char *cmdline);
  38.  
  39. void sigchld_handler(int sig);
  40. void sigtstp_handler(int sig);
  41. void sigint_handler(int sig);
  42. void sigquit_handler(int sig);
  43. void execute_builtin_command(builtin_state builtin);
  44.  
  45.  
  46.  
  47. /*
  48. * <Write main's function header documentation. What does main do?>
  49. * "Each function should be prefaced with a comment describing the purpose
  50. * of the function (in a sentence or two), the function's arguments and
  51. * return value, any error cases that are relevant to the caller,
  52. * any pertinent side effects, and any assumptions that the function makes."
  53. */
  54. int main(int argc, char **argv)
  55. {
  56. char c;
  57. char cmdline[MAXLINE_TSH]; // Cmdline for fgets
  58. bool emit_prompt = true; // Emit prompt (default)
  59.  
  60. // Redirect stderr to stdout (so that driver will get all output
  61. // on the pipe connected to stdout)
  62. Dup2(STDOUT_FILENO, STDERR_FILENO);
  63.  
  64. // Parse the command line
  65. while ((c = getopt(argc, argv, "hvp")) != EOF)
  66. {
  67. switch (c)
  68. {
  69. case 'h': // Prints help message
  70. usage();
  71. break;
  72. case 'v': // Emits additional diagnostic info
  73. verbose = true;
  74. break;
  75. case 'p': // Disables prompt printing
  76. emit_prompt = false;
  77. break;
  78. default:
  79. usage();
  80. }
  81. }
  82.  
  83. // Install the signal handlers
  84. Signal(SIGINT, sigint_handler); // Handles ctrl-c
  85. Signal(SIGTSTP, sigtstp_handler); // Handles ctrl-z
  86. Signal(SIGCHLD, sigchld_handler); // Handles terminated or stopped child
  87.  
  88. Signal(SIGTTIN, SIG_IGN);
  89. Signal(SIGTTOU, SIG_IGN);
  90.  
  91. Signal(SIGQUIT, sigquit_handler);
  92.  
  93. // Initialize the job list
  94. initjobs(job_list);
  95.  
  96. // Execute the shell's read/eval loop
  97. while (true)
  98. {
  99. if (emit_prompt)
  100. {
  101. printf("%s", prompt);
  102. fflush(stdout);
  103. }
  104.  
  105. if ((fgets(cmdline, MAXLINE_TSH, stdin) == NULL) && ferror(stdin))
  106. {
  107. app_error("fgets error");
  108. }
  109.  
  110. if (feof(stdin))
  111. {
  112. // End of file (ctrl-d)
  113. printf ("\n");
  114. fflush(stdout);
  115. fflush(stderr);
  116. return 0;
  117. }
  118.  
  119. // Remove the trailing newline
  120. cmdline[strlen(cmdline)-1] = '\0';
  121.  
  122. // Evaluate the command line
  123. eval(cmdline);
  124.  
  125. fflush(stdout);
  126. }
  127.  
  128. return -1; // control never reaches here
  129. }
  130.  
  131.  
  132. /* Handy guide for eval:
  133. *
  134. * If the user has requested a built-in command (quit, jobs, bg or fg),
  135. * then execute it immediately. Otherwise, fork a child process and
  136. * run the job in the context of the child. If the job is running in
  137. * the foreground, wait for it to terminate and then return.
  138. * Note: each child process must have a unique process group ID so that our
  139. * background children don't receive SIGINT (SIGTSTP) from the kernel
  140. * when we type ctrl-c (ctrl-z) at the keyboard.
  141. */
  142.  
  143. /*
  144. * <What does eval do?>
  145. */
  146.  
  147. void Execve_sachin(const char *filename, char *const argv[], char *const envp[])
  148. {
  149. if (execve(filename, argv, envp) < 0)
  150. printf("%s: Command not found. \n", argv[0]);
  151. }
  152.  
  153. job_state get_job_state(parseline_return parse_result) {
  154.  
  155. if (parse_result == PARSELINE_BG)
  156. return BG;
  157.  
  158. return FG;
  159. }
  160.  
  161. void print_bg_job(int pid) {
  162. sigset_t mask_all, prev_one;
  163.  
  164. Sigfillset(&mask_all);
  165. Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
  166.  
  167. struct job_t *job = getjobpid(job_list, pid);
  168.  
  169. Sigprocmask(SIG_SETMASK, &prev_one, NULL);
  170.  
  171. printf("[%d] (%d) %s\n", job->jid, job->pid, job->cmdline);
  172. }
  173.  
  174.  
  175. void execute_builtin_command(builtin_state builtin) {
  176. if (builtin == BUILTIN_QUIT) {
  177. exit(0);
  178. }
  179. }
  180.  
  181. void eval(const char *cmdline)
  182. {
  183. parseline_return parse_result;
  184. struct cmdline_tokens token;
  185. pid_t pid;
  186. sigset_t mask_all, prev_one, mask_one, empty_set;
  187.  
  188. // Parse command line
  189. parse_result = parseline(cmdline, &token);
  190.  
  191. if (parse_result == PARSELINE_ERROR || parse_result == PARSELINE_EMPTY)
  192. {
  193. return;
  194. }
  195. if (token.builtin != BUILTIN_NONE) {
  196.  
  197. execute_builtin_command(token.builtin);
  198. return;
  199. }
  200.  
  201. job_state state = get_job_state(parse_result);
  202.  
  203. Sigfillset(&mask_all);
  204. Sigemptyset(&mask_one);
  205. Sigemptyset(&empty_set);
  206. Sigaddset(&mask_one, SIGCHLD);
  207.  
  208. Sigprocmask(SIG_BLOCK, &mask_all, &prev_one); // Blocking SIGCHLD
  209.  
  210. if ((pid = Fork()) == 0) {
  211. setpgid(0,0); // Each child process should belong to a different process group
  212. Sigprocmask(SIG_SETMASK, &prev_one, NULL); // Unblocking SIGCHLD for its children
  213. Execve_sachin(token.argv[0], token.argv, environ);
  214. exit(0); // Should never reach here
  215. }
  216. sio_putl(pid);
  217. sio_puts("\n");
  218. //Sigprocmask(SIG_BLOCK, &mask_all, NULL); // Blocking all signals
  219. addjob(job_list, pid, state, cmdline);
  220. Sigprocmask(SIG_SETMASK, &prev_one, NULL); // Unblokcing all signals
  221.  
  222. if (parse_result == PARSELINE_FG) {
  223.  
  224. /* Need to wait for it to complete */
  225. flag = 0;
  226. while (pid != flag) {
  227. sio_puts("Before sigsuspend\n");
  228. Sigsuspend(&empty_set);
  229. sio_puts("After sigsuspend\n");
  230. }
  231. sio_puts("Exited while loop for sigsuspend\n");
  232. }
  233.  
  234. if (parse_result == PARSELINE_BG) {
  235. print_bg_job(pid);
  236. }
  237.  
  238. return;
  239. }
  240.  
  241. /*****************
  242. * Signal handlers
  243. *****************/
  244.  
  245. /*
  246. * <What does sigchld_handler do?>
  247. */
  248. void sigchld_handler(int sig)
  249. {
  250. sio_puts ("In sigchild handler\n");
  251. sigset_t mask_all, prev_all;
  252. pid_t pid;
  253. Sigfillset(&mask_all);
  254. int status;
  255.  
  256. while ((pid = waitpid(-1, &status, WUNTRACED | WNOHANG)) > 0 ) {
  257.  
  258. sio_puts("In while loop of sigchild handler\n");
  259.  
  260. flag = pid;
  261.  
  262. sio_putl(pid);
  263. sio_puts("\n");
  264.  
  265. sio_putl(flag);
  266. sio_puts("\n");
  267.  
  268. if (WIFEXITED(status)) {
  269. Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
  270. deletejob(job_list, pid);
  271. Sigprocmask(SIG_SETMASK, &prev_all, NULL);
  272. sio_puts("Handler reaped child through normal termination \n");
  273. }
  274.  
  275. if (WIFSTOPPED(status)) {
  276. sio_puts("In stopped part of Sigchild handler\n");
  277. }
  278.  
  279. }
  280. sio_puts ("Exiting sigchild handler\n");
  281. return;
  282. }
  283.  
  284. /*
  285. * <What does sigint_handler do?>
  286. */
  287. void sigint_handler(int sig)
  288. {
  289. sio_puts ("In Sigint handler\n");
  290. sigset_t mask_all, prev_one;
  291. Sigfillset(&mask_all); // To do, might have to block only 3 Signals
  292.  
  293. Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
  294. pid_t process_id = fgpid(job_list);
  295. Sigprocmask(SIG_SETMASK, &prev_one, NULL);
  296.  
  297. if (process_id == 0)
  298. return;
  299.  
  300. Kill(-process_id, SIGINT);
  301.  
  302. return;
  303. }
  304.  
  305. /*
  306. * <What does sigtstp_handler do?>
  307. */
  308. void sigtstp_handler(int sig)
  309. {
  310. sio_puts ("In Sigtstp handler\n");
  311. sigset_t mask_all, prev_one;
  312. Sigfillset(&mask_all); // To do, might have to block only 3 Signals
  313.  
  314. Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
  315. pid_t process_id = fgpid(job_list);
  316. Sigprocmask(SIG_SETMASK, &prev_one, NULL);
  317.  
  318. if (process_id == 0)
  319. return;
  320.  
  321. Kill(-process_id, SIGTSTP);
  322.  
  323. return;
  324. }
Advertisement
Add Comment
Please, Sign In to add comment