rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

status.c (3758B)


      1 /* status.c: functions for printing fancy status messages in rc */
      2 
      3 #include "rc.h"
      4 #include "sigmsgs.h"
      5 #include "statval.h"
      6 #include "wait.h"
      7 
      8 /* status == the wait() value of the last command in the pipeline, or the last command */
      9 
     10 static void statprint(pid_t, int);
     11 
     12 static int statuses[512];
     13 static int pipelength = 1;
     14 
     15 /*
     16    Test to see if rc's status is true. According to td, status is true
     17    if and only if every pipe-member has an exit status of zero.
     18 */
     19 
     20 extern int istrue() {
     21 	int i;
     22 	for (i = 0; i < pipelength; i++)
     23 		if (statuses[i] != 0)
     24 			return FALSE;
     25 	return TRUE;
     26 }
     27 
     28 /*
     29    Return the status as an integer. A status which has low-bits set is
     30    a signal number, whereas a status with high bits set is a value set
     31    from exit(). The presence of a signal just sets status to 1. Also,
     32    a pipeline with nonzero exit statuses in it just sets status to 1.
     33 */
     34 
     35 extern int getstatus() {
     36 	int s;
     37 	if (pipelength > 1)
     38 		return !istrue();
     39 	s = statuses[0];
     40 	if (WIFSIGNALED(s))
     41 		return 1;
     42 	return WEXITSTATUS(s);
     43 }
     44 
     45 extern void set(bool code) {
     46 	setstatus(-1, code ? STATUS0 : STATUS1);
     47 }
     48 
     49 /* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */
     50 
     51 extern void setpipestatus(int stats[], int num) {
     52 	int i;
     53 	for (i = 0; i < (pipelength = num); i++) {
     54 		statuses[i] = stats[i];
     55 		statprint(-1, stats[i]);
     56 	}
     57 }
     58 
     59 /* set a simple status, as opposed to a pipeline */
     60 
     61 extern void setstatus(pid_t pid, int i) {
     62 	pipelength = 1;
     63 	statuses[0] = i;
     64 	statprint(pid, i);
     65 }
     66 
     67 /* 
     68    Print a message if called from the wait builitin in an interactive 
     69    shell or termination was with a signal and it is not sigint and
     70    sigpipe or the child dumped core. Exit on error if -e is set.
     71 */
     72 
     73 static void statprint(pid_t pid, int i) {
     74 	int t = WIFSIGNALED(i) ? WTERMSIG(i) : 0;
     75 	const char *core = ((t > 0) && myWIFDUMPED(i) ? "--core dumped" : "");
     76 	if ((interactive && pid != -1) || (t > 0 && (*core || (t != SIGINT && t != SIGPIPE)))) {
     77 		if (pid != -1)
     78 			fprint(2, "%ld: ", (long)pid);
     79 		if (t == 0)
     80 			fprint(2, "done (%d)\n", WEXITSTATUS(i));
     81 		else if ((t > 0) && (t < NUMOFSIGNALS) && *signals[t].msg != '\0')
     82 			fprint(2, "%s%s\n", signals[t].msg, core);
     83 		else
     84 			fprint(2, "unknown signal %d%s\n", t, core);
     85 	}
     86 	if (i != 0 && dashee && !cond)
     87 		rc_exit(getstatus());
     88 }
     89 
     90 /* prepare a list to be passed back. Used whenever $status is dereferenced */
     91 
     92 extern List *sgetstatus() {
     93 	List *r = NULL;
     94 	int i;
     95 
     96 	for (i = 0; i < pipelength; i++) {
     97 		List *q = nnew(List);
     98 		q->w = strstatus(statuses[i]);
     99 		q->m = NULL;
    100 		q->n = r;
    101 		r = q;
    102 	}
    103 
    104 	return r;
    105 }
    106 
    107 /* return status as a string (used above and for bqstatus) */
    108 
    109 extern char *strstatus(int s) {
    110 	if (WIFSIGNALED(s)) {
    111 		int t = WTERMSIG(s);
    112 		const char *core = myWIFDUMPED(s) ? "+core" : "";
    113 		if ((t > 0) && (t < NUMOFSIGNALS) && *signals[t].name != '\0')
    114 			return nprint("%s%s", signals[t].name, core);
    115 		else
    116 			return nprint("-%d%s", t, core); /* unknown signals are negated */
    117 	} else
    118 		return nprint("%d", WEXITSTATUS(s));
    119 }
    120 
    121 extern void ssetstatus(char **av) {
    122 	int i, j, k, l;
    123 	bool found;
    124 	for (l = 0; av[l] != NULL; l++)
    125 		; /* count up array length */
    126 	--l;
    127 	for (i = 0; av[i] != NULL; i++) {
    128 		j = a2u(av[i]);
    129 		if (j >= 0) {
    130 			statuses[l - i] = j << 8;
    131 			continue;
    132 		}
    133 		found = FALSE;
    134 		for (k = 0; k < NUMOFSIGNALS; k++) {
    135 			if (streq(signals[k].name, av[i])) {
    136 				statuses[l - i] = k;
    137 				found = TRUE;
    138 				break;
    139 			}
    140 			else {
    141 				size_t len = strlen(signals[k].name);
    142 				if (strncmp(signals[k].name, av[i], len) == 0 && streq(av[i] + len, "+core")) {
    143 					statuses[l - i] = k + 0x80;
    144 					found = TRUE;
    145 					break;
    146 				}
    147 			}
    148 		}
    149 		if (!found) {
    150 			fprint(2, "bad status\n");
    151 			set(FALSE);
    152 			return;
    153 		}
    154 	}
    155 	pipelength = i;
    156 }