fork download
  1. /*
  2.  * COMP 321 Project 4: Shell
  3.  *
  4.  * This program implements a tiny shell with job control.
  5.  *
  6.  * <Put your name(s) and NetID(s) here>
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <sys/wait.h>
  11.  
  12. #include <assert.h>
  13. #include <ctype.h>
  14. #include <errno.h>
  15. #include <signal.h>
  16. #include <stdbool.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21.  
  22. // You may assume that these constants are large enough.
  23. #define MAXLINE 1024 // max line size
  24. #define MAXARGS 128 // max args on a command line
  25. #define MAXJOBS 16 // max jobs at any point in time
  26. #define MAXJID (1 << 16) // max job ID
  27.  
  28. // The job states are:
  29. #define UNDEF 0 // undefined
  30. #define FG 1 // running in foreground
  31. #define BG 2 // running in background
  32. #define ST 3 // stopped
  33.  
  34. /*
  35.  * The job state transitions and enabling actions are:
  36.  * FG -> ST : ctrl-z
  37.  * ST -> FG : fg command
  38.  * ST -> BG : bg command
  39.  * BG -> FG : fg command
  40.  * At most one job can be in the FG state.
  41.  */
  42.  
  43. struct Job {
  44. pid_t pid; // job PID
  45. int jid; // job ID [1, 2, ...]
  46. int state; // UNDEF, FG, BG, or ST
  47. char cmdline[MAXLINE]; // command line
  48. };
  49. typedef volatile struct Job *JobP;
  50.  
  51. /*
  52.  * Define the jobs list using the "volatile" qualifier because it is accessed
  53.  * by a signal handler (as well as the main program).
  54.  */
  55. static volatile struct Job jobs[MAXJOBS];
  56. static int nextjid = 1; // next job ID to allocate
  57.  
  58. extern char **environ; // defined by libc
  59.  
  60. static char prompt[] = "tsh> "; // command line prompt (DO NOT CHANGE)
  61. static bool verbose = false; // If true, print additional output.
  62.  
  63. /*
  64.  * The following array can be used to map a signal number to its name.
  65.  * This mapping is valid for x86(-64)/Linux systems, such as CLEAR.
  66.  * The mapping for other versions of Unix, such as FreeBSD, Mac OS X, or
  67.  * Solaris, differ!
  68.  */
  69. static const char *const signame[NSIG] = {
  70. "Signal 0",
  71. "HUP", /* SIGHUP */
  72. "INT", /* SIGINT */
  73. "QUIT", /* SIGQUIT */
  74. "ILL", /* SIGILL */
  75. "TRAP", /* SIGTRAP */
  76. "ABRT", /* SIGABRT */
  77. "BUS", /* SIGBUS */
  78. "FPE", /* SIGFPE */
  79. "KILL", /* SIGKILL */
  80. "USR1", /* SIGUSR1 */
  81. "SEGV", /* SIGSEGV */
  82. "USR2", /* SIGUSR2 */
  83. "PIPE", /* SIGPIPE */
  84. "ALRM", /* SIGALRM */
  85. "TERM", /* SIGTERM */
  86. "STKFLT", /* SIGSTKFLT */
  87. "CHLD", /* SIGCHLD */
  88. "CONT", /* SIGCONT */
  89. "STOP", /* SIGSTOP */
  90. "TSTP", /* SIGTSTP */
  91. "TTIN", /* SIGTTIN */
  92. "TTOU", /* SIGTTOU */
  93. "URG", /* SIGURG */
  94. "XCPU", /* SIGXCPU */
  95. "XFSZ", /* SIGXFSZ */
  96. "VTALRM", /* SIGVTALRM */
  97. "PROF", /* SIGPROF */
  98. "WINCH", /* SIGWINCH */
  99. "IO", /* SIGIO */
  100. "PWR", /* SIGPWR */
  101. "Signal 31"
  102. };
  103.  
  104. // You must implement the following functions:
  105.  
  106. static int builtin_cmd(char **argv);
  107. static void do_bgfg(char **argv);
  108. static void eval(const char *cmdline);
  109. static void initpath(const char *pathstr);
  110. static void waitfg(pid_t pid);
  111.  
  112. static void sigchld_handler(int signum);
  113. static void sigint_handler(int signum);
  114. static void sigtstp_handler(int signum);
  115.  
  116. // We are providing the following functions to you:
  117.  
  118. static int parseline(const char *cmdline, char **argv);
  119.  
  120. static void sigquit_handler(int signum);
  121.  
  122. static int addjob(JobP jobs, pid_t pid, int state, const char *cmdline);
  123. static void clearjob(JobP job);
  124. static int deletejob(JobP jobs, pid_t pid);
  125. static pid_t fgpid(JobP jobs);
  126. static JobP getjobjid(JobP jobs, int jid);
  127. static JobP getjobpid(JobP jobs, pid_t pid);
  128. static void initjobs(JobP jobs);
  129. static void listjobs(JobP jobs);
  130. static int maxjid(JobP jobs);
  131. static int pid2jid(pid_t pid);
  132.  
  133. static void app_error(const char *msg);
  134. static void unix_error(const char *msg);
  135. static void usage(void);
  136.  
  137. typedef void handler_t(int);
  138. static handler_t *Signal(int signum, handler_t *handler);
  139.  
  140. static void Sio_error(char s[]);
  141. static ssize_t Sio_putl(long v);
  142. static ssize_t Sio_puts(char s[]);
  143. static void sio_error(char s[]);
  144. static void sio_ltoa(long v, char s[], int b);
  145. static ssize_t sio_putl(long v);
  146. static ssize_t sio_puts(char s[]);
  147. static void sio_reverse(char s[]);
  148. static size_t sio_strlen(char s[]);
  149.  
  150. /*
  151.  * main - The shell's main routine
  152.  *
  153.  * Requires:
  154.  * <???>
  155.  *
  156.  * Effects:
  157.  * <???>
  158.  */
  159. int
  160. main(int argc, char **argv)
  161. {
  162. int c;
  163. char cmdline[MAXLINE];
  164. char *path = NULL;
  165. bool emit_prompt = true; // Emit a prompt by default.
  166.  
  167. /*
  168. * Redirect stderr to stdout (so that driver will get all output
  169. * on the pipe connected to stdout).
  170. */
  171. dup2(1, 2);
  172.  
  173. // Parse the command line.
  174. while ((c = getopt(argc, argv, "hvp")) != -1) {
  175. switch (c) {
  176. case 'h': // Print a help message.
  177. usage();
  178. break;
  179. case 'v': // Emit additional diagnostic info.
  180. verbose = true;
  181. break;
  182. case 'p': // Don't print a prompt.
  183. // This is handy for automatic testing.
  184. emit_prompt = false;
  185. break;
  186. default:
  187. usage();
  188. }
  189. }
  190.  
  191. // Install the signal handlers.
  192.  
  193. // These are the ones you will need to implement:
  194. Signal(SIGINT, sigint_handler); // ctrl-c
  195. Signal(SIGTSTP, sigtstp_handler); // ctrl-z
  196. Signal(SIGCHLD, sigchld_handler); // Terminated or stopped child
  197.  
  198. // This one provides a clean way to kill the shell.
  199. Signal(SIGQUIT, sigquit_handler);
  200.  
  201. // Initialize the search path.
  202. path = getenv("PATH");
  203. initpath(path);
  204.  
  205. // Initialize the jobs list.
  206. initjobs(jobs);
  207.  
  208. // Execute the shell's read/eval loop.
  209. while (true) {
  210.  
  211. // Read the command line.
  212. if (emit_prompt) {
  213. printf("%s", prompt);
  214. fflush(stdout);
  215. }
  216. if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin))
  217. app_error("fgets error");
  218. if (feof(stdin)) { // End of file (ctrl-d)
  219. fflush(stdout);
  220. exit(0);
  221. }
  222.  
  223. // Evaluate the command line.
  224. eval(cmdline);
  225. fflush(stdout);
  226. fflush(stdout);
  227. }
  228.  
  229. // Control never reaches here.
  230. assert(false);
  231. }
  232.  
  233. /*
  234.  * eval - Evaluate the command line that the user has just typed in.
  235.  *
  236.  * If the user has requested a built-in command (quit, jobs, bg or fg)
  237.  * then execute it immediately. Otherwise, fork a child process and
  238.  * run the job in the context of the child. If the job is running in
  239.  * the foreground, wait for it to terminate and then return. Note:
  240.  * each child process must have a unique process group ID so that our
  241.  * background children don't receive SIGINT (SIGTSTP) from the kernel
  242.  * when we type ctrl-c (ctrl-z) at the keyboard.
  243.  *
  244.  * Requires:
  245.  * <???>
  246.  *
  247.  * Effects:
  248.  * <???>
  249.  */
  250. static void
  251. eval(const char *cmdline)
  252. {
  253.  
  254. // Prevent an "unused parameter" warning. REMOVE THIS STATEMENT!
  255. (void)cmdline;
  256. }
  257.  
  258. /*
  259.  * parseline - Parse the command line and build the argv array.
  260.  *
  261.  * Requires:
  262.  * "cmdline" is a NUL ('\0') terminated string with a trailing
  263.  * '\n' character. "cmdline" must contain less than MAXARGS
  264.  * arguments.
  265.  *
  266.  * Effects:
  267.  * Builds "argv" array from space delimited arguments on the command line.
  268.  * The final element of "argv" is set to NULL. Characters enclosed in
  269.  * single quotes are treated as a single argument. Returns true if
  270.  * the user has requested a BG job and false if the user has requested
  271.  * a FG job.
  272.  */
  273. static int
  274. parseline(const char *cmdline, char **argv)
  275. {
  276. int argc; // number of args
  277. int bg; // background job?
  278. static char array[MAXLINE]; // local copy of command line
  279. char *buf = array; // ptr that traverses command line
  280. char *delim; // points to first space delimiter
  281.  
  282. strcpy(buf, cmdline);
  283.  
  284. // Replace trailing '\n' with space.
  285. buf[strlen(buf) - 1] = ' ';
  286.  
  287. // Ignore leading spaces.
  288. while (*buf != '\0' && *buf == ' ')
  289. buf++;
  290.  
  291. // Build the argv list.
  292. argc = 0;
  293. if (*buf == '\'') {
  294. buf++;
  295. delim = strchr(buf, '\'');
  296. } else
  297. delim = strchr(buf, ' ');
  298. while (delim != NULL) {
  299. argv[argc++] = buf;
  300. *delim = '\0';
  301. buf = delim + 1;
  302. while (*buf != '\0' && *buf == ' ') // Ignore spaces.
  303. buf++;
  304. if (*buf == '\'') {
  305. buf++;
  306. delim = strchr(buf, '\'');
  307. } else
  308. delim = strchr(buf, ' ');
  309. }
  310. argv[argc] = NULL;
  311.  
  312. // Ignore blank line.
  313. if (argc == 0)
  314. return (1);
  315.  
  316. // Should the job run in the background?
  317. if ((bg = (*argv[argc - 1] == '&')) != 0)
  318. argv[--argc] = NULL;
  319.  
  320. return (bg);
  321. }
  322.  
  323. /*
  324.  * builtin_cmd - If the user has typed a built-in command then execute
  325.  * it immediately.
  326.  *
  327.  * Requires:
  328.  * <???>
  329.  *
  330.  * Effects:
  331.  * <???>
  332.  */
  333. static int
  334. builtin_cmd(char **argv)
  335. {
  336.  
  337. // Prevent an "unused parameter" warning. REMOVE THIS STATEMENT!
  338. (void)argv;
  339. return (0); // This is not a built-in command.
  340. }
  341.  
  342. /*
  343.  * do_bgfg - Execute the built-in bg and fg commands.
  344.  *
  345.  * Requires:
  346.  * <???>
  347.  *
  348.  * Effects:
  349.  * <???>
  350.  */
  351. static void
  352. do_bgfg(char **argv)
  353. {
  354.  
  355. // Prevent an "unused parameter" warning. REMOVE THIS STATEMENT!
  356. (void)argv;
  357. }
  358.  
  359. /*
  360.  * waitfg - Block until process pid is no longer the foreground process.
  361.  *
  362.  * Requires:
  363.  * <???>
  364.  *
  365.  * Effects:
  366.  * <???>
  367.  */
  368. static void
  369. waitfg(pid_t pid)
  370. {
  371.  
  372. // Prevent an "unused parameter" warning. REMOVE THIS STATEMENT!
  373. (void)pid;
  374. }
  375.  
  376. /*
  377.  * initpath - Perform all necessary initialization of the search path,
  378.  * which may be simply saving the path.
  379.  *
  380.  * Requires:
  381.  * "pathstr" is a valid search path.
  382.  *
  383.  * Effects:
  384.  * <???>
  385.  */
  386. static void
  387. initpath(const char *pathstr)
  388. {
  389.  
  390. // Prevent an "unused parameter" warning. REMOVE THIS STATEMENT!
  391. (void)pathstr;
  392. }
  393.  
  394. /*
  395.  * The signal handlers follow.
  396.  */
  397.  
  398. /*
  399.  * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever
  400.  * a child job terminates (becomes a zombie), or stops because it
  401.  * received a SIGSTOP or SIGTSTP signal. The handler reaps all
  402.  * available zombie children, but doesn't wait for any other
  403.  * currently running children to terminate.
  404.  *
  405.  * Requires:
  406.  * <???>
  407.  *
  408.  * Effects:
  409.  * <???>
  410.  */
  411. static void
  412. sigchld_handler(int signum)
  413. {
  414.  
  415. // Prevent an "unused parameter" warning.
  416. (void)signum;
  417. }
  418.  
  419. /*
  420.  * sigint_handler - The kernel sends a SIGINT to the shell whenever the
  421.  * user types ctrl-c at the keyboard. Catch it and send it along
  422.  * to the foreground job.
  423.  *
  424.  * Requires:
  425.  * <???>
  426.  *
  427.  * Effects:
  428.  * <???>
  429.  */
  430. static void
  431. sigint_handler(int signum)
  432. {
  433.  
  434. // Prevent an "unused parameter" warning.
  435. (void)signum;
  436. }
  437.  
  438. /*
  439.  * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
  440.  * the user types ctrl-z at the keyboard. Catch it and suspend the
  441.  * foreground job by sending it a SIGTSTP.
  442.  *
  443.  * Requires:
  444.  * <???>
  445.  *
  446.  * Effects:
  447.  * <???>
  448.  */
  449. static void
  450. sigtstp_handler(int signum)
  451. {
  452.  
  453. // Prevent an "unused parameter" warning.
  454. (void)signum;
  455. }
  456.  
  457. /*
  458.  * sigquit_handler - The driver program can gracefully terminate the
  459.  * child shell by sending it a SIGQUIT signal.
  460.  *
  461.  * Requires:
  462.  * "signum" is SIGQUIT.
  463.  *
  464.  * Effects:
  465.  * Terminates the program.
  466.  */
  467. static void
  468. sigquit_handler(int signum)
  469. {
  470.  
  471. // Prevent an "unused parameter" warning.
  472. (void)signum;
  473. Sio_puts("Terminating after receipt of SIGQUIT signal\n");
  474. _exit(1);
  475. }
  476.  
  477. /*
  478.  * This comment marks the end of the signal handlers.
  479.  */
  480.  
  481. /*
  482.  * The following helper routines manipulate the jobs list.
  483.  */
  484.  
  485. /*
  486.  * Requires:
  487.  * "job" points to a job structure.
  488.  *
  489.  * Effects:
  490.  * Clears the fields in the referenced job structure.
  491.  */
  492. static void
  493. clearjob(JobP job)
  494. {
  495.  
  496. job->pid = 0;
  497. job->jid = 0;
  498. job->state = UNDEF;
  499. job->cmdline[0] = '\0';
  500. }
  501.  
  502. /*
  503.  * Requires:
  504.  * "jobs" points to an array of MAXJOBS job structures.
  505.  *
  506.  * Effects:
  507.  * Initializes the jobs list to an empty state.
  508.  */
  509. static void
  510. initjobs(JobP jobs)
  511. {
  512. int i;
  513.  
  514. for (i = 0; i < MAXJOBS; i++)
  515. clearjob(&jobs[i]);
  516. }
  517.  
  518. /*
  519.  * Requires:
  520.  * "jobs" points to an array of MAXJOBS job structures.
  521.  *
  522.  * Effects:
  523.  * Returns the largest allocated job ID.
  524.  */
  525. static int
  526. maxjid(JobP jobs)
  527. {
  528. int i, max = 0;
  529.  
  530. for (i = 0; i < MAXJOBS; i++)
  531. if (jobs[i].jid > max)
  532. max = jobs[i].jid;
  533. return (max);
  534. }
  535.  
  536. /*
  537.  * Requires:
  538.  * "jobs" points to an array of MAXJOBS job structures, and "cmdline" is
  539.  * a properly terminated string.
  540.  *
  541.  * Effects:
  542.  * Adds a job to the jobs list.
  543.  */
  544. static int
  545. addjob(JobP jobs, pid_t pid, int state, const char *cmdline)
  546. {
  547. int i;
  548.  
  549. if (pid < 1)
  550. return (0);
  551. for (i = 0; i < MAXJOBS; i++) {
  552. if (jobs[i].pid == 0) {
  553. jobs[i].pid = pid;
  554. jobs[i].state = state;
  555. jobs[i].jid = nextjid++;
  556. if (nextjid > MAXJOBS)
  557. nextjid = 1;
  558. // Remove the "volatile" qualifier using a cast.
  559. strcpy((char *)jobs[i].cmdline, cmdline);
  560. if (verbose) {
  561. printf("Added job [%d] %d %s\n", jobs[i].jid,
  562. (int)jobs[i].pid, jobs[i].cmdline);
  563. }
  564. return (1);
  565. }
  566. }
  567. printf("Tried to create too many jobs\n");
  568. return (0);
  569. }
  570.  
  571. /*
  572.  * Requires:
  573.  * "jobs" points to an array of MAXJOBS job structures.
  574.  *
  575.  * Effects:
  576.  * Deletes a job from the jobs list whose PID equals "pid".
  577.  */
  578. static int
  579. deletejob(JobP jobs, pid_t pid)
  580. {
  581. int i;
  582.  
  583. if (pid < 1)
  584. return (0);
  585. for (i = 0; i < MAXJOBS; i++) {
  586. if (jobs[i].pid == pid) {
  587. clearjob(&jobs[i]);
  588. nextjid = maxjid(jobs) + 1;
  589. return (1);
  590. }
  591. }
  592. return (0);
  593. }
  594.  
  595. /*
  596.  * Requires:
  597.  * "jobs" points to an array of MAXJOBS job structures.
  598.  *
  599.  * Effects:
  600.  * Returns the PID of the current foreground job or 0 if no foreground
  601.  * job exists.
  602.  */
  603. static pid_t
  604. fgpid(JobP jobs)
  605. {
  606. int i;
  607.  
  608. for (i = 0; i < MAXJOBS; i++)
  609. if (jobs[i].state == FG)
  610. return (jobs[i].pid);
  611. return (0);
  612. }
  613.  
  614. /*
  615.  * Requires:
  616.  * "jobs" points to an array of MAXJOBS job structures.
  617.  *
  618.  * Effects:
  619.  * Returns a pointer to the job structure with process ID "pid" or NULL if
  620.  * no such job exists.
  621.  */
  622. static JobP
  623. getjobpid(JobP jobs, pid_t pid)
  624. {
  625. int i;
  626.  
  627. if (pid < 1)
  628. return (NULL);
  629. for (i = 0; i < MAXJOBS; i++)
  630. if (jobs[i].pid == pid)
  631. return (&jobs[i]);
  632. return (NULL);
  633. }
  634.  
  635. /*
  636.  * Requires:
  637.  * "jobs" points to an array of MAXJOBS job structures.
  638.  *
  639.  * Effects:
  640.  * Returns a pointer to the job structure with job ID "jid" or NULL if no
  641.  * such job exists.
  642.  */
  643. static JobP
  644. getjobjid(JobP jobs, int jid)
  645. {
  646. int i;
  647.  
  648. if (jid < 1)
  649. return (NULL);
  650. for (i = 0; i < MAXJOBS; i++)
  651. if (jobs[i].jid == jid)
  652. return (&jobs[i]);
  653. return (NULL);
  654. }
  655.  
  656. /*
  657.  * Requires:
  658.  * Nothing.
  659.  *
  660.  * Effects:
  661.  * Returns the job ID for the job with process ID "pid" or 0 if no such
  662.  * job exists.
  663.  */
  664. static int
  665. pid2jid(pid_t pid)
  666. {
  667. int i;
  668.  
  669. if (pid < 1)
  670. return (0);
  671. for (i = 0; i < MAXJOBS; i++)
  672. if (jobs[i].pid == pid)
  673. return (jobs[i].jid);
  674. return (0);
  675. }
  676.  
  677. /*
  678.  * Requires:
  679.  * "jobs" points to an array of MAXJOBS job structures.
  680.  *
  681.  * Effects:
  682.  * Prints the jobs list.
  683.  */
  684. static void
  685. listjobs(JobP jobs)
  686. {
  687. int i;
  688.  
  689. for (i = 0; i < MAXJOBS; i++) {
  690. if (jobs[i].pid != 0) {
  691. printf("[%d] (%d) ", jobs[i].jid, (int)jobs[i].pid);
  692. switch (jobs[i].state) {
  693. case BG:
  694. printf("Running ");
  695. break;
  696. case FG:
  697. printf("Foreground ");
  698. break;
  699. case ST:
  700. printf("Stopped ");
  701. break;
  702. default:
  703. printf("listjobs: Internal error: "
  704. "job[%d].state=%d ", i, jobs[i].state);
  705. }
  706. printf("%s", jobs[i].cmdline);
  707. }
  708. }
  709. }
  710.  
  711. /*
  712.  * This comment marks the end of the jobs list helper routines.
  713.  */
  714.  
  715. /*
  716.  * Other helper routines follow.
  717.  */
  718.  
  719. /*
  720.  * Requires:
  721.  * Nothing.
  722.  *
  723.  * Effects:
  724.  * Prints a help message.
  725.  */
  726. static void
  727. usage(void)
  728. {
  729.  
  730. printf("Usage: shell [-hvp]\n");
  731. printf(" -h print this message\n");
  732. printf(" -v print additional diagnostic information\n");
  733. printf(" -p do not emit a command prompt\n");
  734. exit(1);
  735. }
  736.  
  737. /*
  738.  * Requires:
  739.  * "msg" is a properly terminated string.
  740.  *
  741.  * Effects:
  742.  * Prints a Unix-style error message and terminates the program.
  743.  */
  744. static void
  745. unix_error(const char *msg)
  746. {
  747.  
  748. fprintf(stdout, "%s: %s\n", msg, strerror(errno));
  749. exit(1);
  750. }
  751.  
  752. /*
  753.  * Requires:
  754.  * "msg" is a properly terminated string.
  755.  *
  756.  * Effects:
  757.  * Prints "msg" and terminates the program.
  758.  */
  759. static void
  760. app_error(const char *msg)
  761. {
  762.  
  763. fprintf(stdout, "%s\n", msg);
  764. exit(1);
  765. }
  766.  
  767. /*
  768.  * Requires:
  769.  * "signum" is a valid signal number, and "handler" is a valid signal
  770.  * handler.
  771.  *
  772.  * Effects:
  773.  * Registers a new handler for the specified signal, returning the old
  774.  * handler. Behaves similarly to "sigset" but restarts system calls
  775.  * when possible.
  776.  */
  777. static handler_t *
  778. Signal(int signum, handler_t *handler)
  779. {
  780. struct sigaction action, old_action;
  781.  
  782. action.sa_handler = handler;
  783. sigemptyset(&action.sa_mask); // Block sigs of type being handled.
  784. action.sa_flags = SA_RESTART; // Restart syscalls if possible.
  785. if (sigaction(signum, &action, &old_action) < 0)
  786. unix_error("Signal error");
  787. return (old_action.sa_handler);
  788. }
  789.  
  790. /*
  791.  * Requires:
  792.  * The character array "s" is sufficiently large to store the ASCII
  793.  * representation of the long "v" in base "b".
  794.  *
  795.  * Effects:
  796.  * Converts a long "v" to a base "b" string, storing that string in the
  797.  * character array "s" (from K&R). This function can be safely called by
  798.  * a signal handler.
  799.  */
  800. static void
  801. sio_ltoa(long v, char s[], int b)
  802. {
  803. int c, i = 0;
  804.  
  805. do
  806. s[i++] = (c = v % b) < 10 ? c + '0' : c - 10 + 'a';
  807. while ((v /= b) > 0);
  808. s[i] = '\0';
  809. sio_reverse(s);
  810. }
  811.  
  812. /*
  813.  * Requires:
  814.  * "s" is a properly terminated string.
  815.  *
  816.  * Effects:
  817.  * Reverses a string (from K&R). This function can be safely called by a
  818.  * signal handler.
  819.  */
  820. static void
  821. sio_reverse(char s[])
  822. {
  823. int c, i, j;
  824.  
  825. for (i = 0, j = sio_strlen(s) - 1; i < j; i++, j--) {
  826. c = s[i];
  827. s[i] = s[j];
  828. s[j] = c;
  829. }
  830. }
  831.  
  832. /*
  833.  * Requires:
  834.  * "s" is a properly terminated string.
  835.  *
  836.  * Effects:
  837.  * Computes and returns the length of the string "s". This function can be
  838.  * safely called by a signal handler.
  839.  */
  840. static size_t
  841. sio_strlen(char s[])
  842. {
  843. size_t i = 0;
  844.  
  845. while (s[i] != '\0')
  846. i++;
  847. return (i);
  848. }
  849.  
  850. /*
  851.  * Requires:
  852.  * None.
  853.  *
  854.  * Effects:
  855.  * Prints the long "v" to stdout using only functions that can be safely
  856.  * called by a signal handler, and returns either the number of characters
  857.  * printed or -1 if the long could not be printed.
  858.  */
  859. static ssize_t
  860. sio_putl(long v)
  861. {
  862. char s[128];
  863.  
  864. sio_ltoa(v, s, 10);
  865. return (sio_puts(s));
  866. }
  867.  
  868. /*
  869.  * Requires:
  870.  * "s" is a properly terminated string.
  871.  *
  872.  * Effects:
  873.  * Prints the string "s" to stdout using only functions that can be safely
  874.  * called by a signal handler, and returns either the number of characters
  875.  * printed or -1 if the string could not be printed.
  876.  */
  877. static ssize_t
  878. sio_puts(char s[])
  879. {
  880.  
  881. return (write(STDOUT_FILENO, s, sio_strlen(s)));
  882. }
  883.  
  884. /*
  885.  * Requires:
  886.  * "s" is a properly terminated string.
  887.  *
  888.  * Effects:
  889.  * Prints the string "s" to stdout using only functions that can be safely
  890.  * called by a signal handler, and exits the program.
  891.  */
  892. static void
  893. sio_error(char s[])
  894. {
  895.  
  896. sio_puts(s);
  897. _exit(1);
  898. }
  899.  
  900. /*
  901.  * Requires:
  902.  * None.
  903.  *
  904.  * Effects:
  905.  * Prints the long "v" to stdout using only functions that can be safely
  906.  * called by a signal handler. Either returns the number of characters
  907.  * printed or exits if the long could not be printed.
  908.  */
  909. static ssize_t
  910. Sio_putl(long v)
  911. {
  912. ssize_t n;
  913.  
  914. if ((n = sio_putl(v)) < 0)
  915. sio_error("Sio_putl error");
  916. return (n);
  917. }
  918.  
  919. /*
  920.  * Requires:
  921.  * "s" is a properly terminated string.
  922.  *
  923.  * Effects:
  924.  * Prints the string "s" to stdout using only functions that can be safely
  925.  * called by a signal handler. Either returns the number of characters
  926.  * printed or exits if the string could not be printed.
  927.  */
  928. static ssize_t
  929. Sio_puts(char s[])
  930. {
  931. ssize_t n;
  932.  
  933. if ((n = sio_puts(s)) < 0)
  934. sio_error("Sio_puts error");
  935. return (n);
  936. }
  937.  
  938. /*
  939.  * Requires:
  940.  * "s" is a properly terminated string.
  941.  *
  942.  * Effects:
  943.  * Prints the string "s" to stdout using only functions that can be safely
  944.  * called by a signal handler, and exits the program.
  945.  */
  946. static void
  947. Sio_error(char s[])
  948. {
  949.  
  950. sio_error(s);
  951. }
  952.  
  953. // Prevent "unused function" and "unused variable" warnings.
  954. static const void *dummy_ref[] = { Sio_error, Sio_putl, addjob, builtin_cmd,
  955. deletejob, do_bgfg, dummy_ref, fgpid, getjobjid, getjobpid, listjobs,
  956. parseline, pid2jid, signame, waitfg };
  957.  
  958. /*
  959.  * The last lines of this file configure the behavior of the "Tab" key in
  960.  * emacs. Emacs has a rudimentary understanding of C syntax and style. In
  961.  * particular, depressing the "Tab" key once at the start of a new line will
  962.  * insert as many tabs and/or spaces as are needed for proper indentation.
  963.  */
  964.  
  965. /* Local Variables: */
  966. /* mode: c */
  967. /* c-default-style: "bsd" */
  968. /* c-basic-offset: 8 */
  969. /* c-continued-statement-offset: 4 */
  970. /* indent-tabs-mode: t */
  971. /* End: */
  972.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.c:69:34: error: ‘NSIG’ undeclared here (not in a function)
 static const char *const signame[NSIG] = {
                                  ^~~~
prog.c: In function ‘main’:
prog.c:174:14: warning: implicit declaration of function ‘getopt’ [-Wimplicit-function-declaration]
  while ((c = getopt(argc, argv, "hvp")) != -1) {
              ^~~~~~
prog.c: In function ‘Signal’:
prog.c:780:19: error: storage size of ‘action’ isn’t known
  struct sigaction action, old_action;
                   ^~~~~~
prog.c:780:27: error: storage size of ‘old_action’ isn’t known
  struct sigaction action, old_action;
                           ^~~~~~~~~~
prog.c:783:2: warning: implicit declaration of function ‘sigemptyset’ [-Wimplicit-function-declaration]
  sigemptyset(&action.sa_mask); // Block sigs of type being handled.
  ^~~~~~~~~~~
prog.c:784:20: error: ‘SA_RESTART’ undeclared (first use in this function)
  action.sa_flags = SA_RESTART; // Restart syscalls if possible.
                    ^~~~~~~~~~
prog.c:784:20: note: each undeclared identifier is reported only once for each function it appears in
prog.c:785:6: warning: implicit declaration of function ‘sigaction’ [-Wimplicit-function-declaration]
  if (sigaction(signum, &action, &old_action) < 0)
      ^~~~~~~~~
prog.c:780:27: warning: unused variable ‘old_action’ [-Wunused-variable]
  struct sigaction action, old_action;
                           ^~~~~~~~~~
prog.c:780:19: warning: unused variable ‘action’ [-Wunused-variable]
  struct sigaction action, old_action;
                   ^~~~~~
prog.c:788:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
At top level:
prog.c:69:26: warning: ‘signame’ defined but not used [-Wunused-variable]
 static const char *const signame[NSIG] = {
                          ^~~~~~~
stdout
Standard output is empty