fn.c (6423B)
1 /* 2 fn.c: functions for adding and deleting functions from the symbol table. 3 Support for signal handlers is also found here. 4 */ 5 6 #include "rc.h" 7 8 #include <signal.h> 9 #include <errno.h> 10 11 #include "input.h" 12 #include "sigmsgs.h" 13 14 static void fn_handler(int), dud_handler(int); 15 16 static bool runexit = FALSE; 17 static Node *handlers[NUMOFSIGNALS], null; 18 static void (*def_sigint)(int) = SIG_DFL; 19 static void (*def_sigquit)(int) = SIG_DFL; 20 static void (*def_sigterm)(int) = SIG_DFL; 21 22 /* 23 Set signals to default values for rc. This means that interactive 24 shells ignore SIGTERM, etc. 25 */ 26 27 extern void inithandler() { 28 int i; 29 null.type = nBody; 30 null.u[0].p = null.u[1].p = NULL; 31 for (i = 1; i < NUMOFSIGNALS; i++) 32 if (i != SIGCHLD && sighandlers[i] == SIG_IGN) 33 fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */ 34 if (interactive || sighandlers[SIGINT] != SIG_IGN) { 35 def_sigint = sigint; 36 fnrm("sigint"); /* installs SIGINT catcher if not inherited ignored */ 37 } 38 if (!dashdee) { 39 if (interactive || sighandlers[SIGQUIT] != SIG_IGN) { 40 def_sigquit = dud_handler; 41 fnrm("sigquit"); /* "ignores" SIGQUIT unless inherited ignored */ 42 } 43 if (interactive) { 44 def_sigterm = dud_handler; 45 fnrm("sigterm"); /* ditto for SIGTERM */ 46 } 47 } 48 } 49 50 /* only run this in a child process! resets signals to their default values */ 51 52 extern void setsigdefaults(bool sysvbackground) { 53 int i; 54 /* 55 General housekeeping: setsigdefaults happens after fork(), 56 so it's a convenient place to clean up open file descriptors. 57 (history file, scripts, etc.) 58 */ 59 closefds(); 60 /* 61 Restore signals to SIG_DFL, paying close attention to 62 a few quirks: SIGINT, SIGQUIT and are treated specially 63 depending on whether we are doing v7-style backgrounding 64 or not; the default action for SIGINT, SIGQUIT and SIGTERM 65 must be set to the appropriate action; finally, care must 66 be taken not to set to SIG_DFL any signals which are being 67 ignored. 68 */ 69 for (i = 1; i < NUMOFSIGNALS; i++) 70 if (sighandlers[i] != SIG_IGN) { 71 handlers[i] = NULL; 72 switch (i) { 73 case SIGINT: 74 if (sysvbackground) { 75 def_sigint = SIG_IGN; 76 fnassign("sigint", NULL); /* ignore */ 77 } else { 78 def_sigint = SIG_DFL; 79 goto sigcommon; 80 } 81 break; 82 case SIGQUIT: 83 if (sysvbackground) { 84 def_sigquit = SIG_IGN; 85 fnassign("sigquit", NULL); /* ignore */ 86 } else { 87 def_sigquit = SIG_DFL; 88 goto sigcommon; 89 } 90 break; 91 case SIGTERM: 92 def_sigterm = SIG_DFL; 93 /* FALLTHROUGH */ 94 sigcommon: 95 default: 96 if (sighandlers[i] != SIG_DFL) { 97 rc_signal(i, SIG_DFL); 98 delete_fn(signals[i].name); 99 } 100 } 101 } 102 delete_fn("sigexit"); 103 runexit = FALSE; /* No sigexit on subshells */ 104 } 105 106 /* rc's exit. if runexit is set, run the sigexit function. */ 107 108 extern void rc_exit(int stat) { 109 if (runexit) { 110 char *sig[2]; 111 sig[0] = "sigexit"; 112 sig[1] = NULL; 113 runexit = FALSE; 114 funcall(sig); 115 stat = getstatus(); 116 } 117 exit(stat); 118 } 119 120 /* The signal handler for all functions. calls walk() */ 121 122 static void fn_handler(int s) { 123 char *sig[2]; 124 int olderrno; 125 if (s < 1 || s >= NUMOFSIGNALS) 126 panic("unknown signal"); 127 olderrno = errno; 128 sig[0] = signals[s].name; 129 sig[1] = NULL; 130 funcall(sig); 131 errno = olderrno; 132 } 133 134 /* A dud signal handler for SIGQUIT and SIGTERM */ 135 136 static void dud_handler(int ignore) { 137 } 138 139 /* 140 Assign a function in Node form. Check to see if the function is also 141 a signal, and set the signal vectors appropriately. 142 */ 143 144 extern void fnassign(char *name, Node *def) { 145 Node *newdef = treecpy(def == NULL ? &null : def, ealloc); /* important to do the treecopy first */ 146 rc_Function *new = get_fn_place(name); 147 int i; 148 new->def = newdef; 149 new->extdef = NULL; 150 if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */ 151 if (streq(name, "sigchld") || streq(name, "sigcld")) 152 rc_error("can't trap SIGCHLD"); 153 if (streq(name, "sigexit")) 154 runexit = TRUE; 155 for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */ 156 if (streq(signals[i].name, name)) { 157 handlers[i] = newdef; 158 if (def == NULL) 159 rc_signal(i, SIG_IGN); 160 else 161 rc_signal(i, fn_handler); 162 break; 163 } 164 } 165 } 166 167 /* Assign a function from the environment. Store just the external representation */ 168 169 extern void fnassign_string(char *extdef) { 170 char *name = get_name(extdef+3); /* +3 to skip over "fn_" */ 171 rc_Function *new; 172 if (name == NULL) 173 return; 174 new = get_fn_place(name); 175 new->def = NULL; 176 new->extdef = ecpy(extdef); 177 } 178 179 /* Return a function in Node form, evaluating an entry from the environment if necessary */ 180 181 extern Node *fnlookup(char *name) { 182 rc_Function *look = lookup_fn(name); 183 Node *ret; 184 if (look == NULL) 185 return NULL; /* not found */ 186 if (look->def != NULL) 187 return look->def; 188 if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */ 189 return &null; 190 ret = parse_fn(look->extdef); 191 if (ret == NULL) { 192 efree(look->extdef); 193 look->extdef = NULL; 194 return &null; 195 } else { 196 return look->def = treecpy(ret, ealloc); /* Need to take it out of nalloc space */ 197 } 198 } 199 200 /* Return a function in string form (used by makeenv) */ 201 202 extern char *fnlookup_string(char *name) { 203 rc_Function *look = lookup_fn(name); 204 205 if (look == NULL) 206 return NULL; 207 if (look->extdef != NULL) 208 return look->extdef; 209 return look->extdef = mprint("fn_%F={%T}", name, look->def); 210 } 211 212 /* 213 Remove a function from the symbol table. If it also defines a signal 214 handler, restore the signal handler to its default value. 215 */ 216 217 extern void fnrm(char *name) { 218 int i; 219 for (i = 1; i < NUMOFSIGNALS; i++) 220 if (streq(signals[i].name, name)) { 221 handlers[i] = NULL; 222 switch (i) { 223 case SIGINT: 224 rc_signal(i, def_sigint); 225 break; 226 case SIGQUIT: 227 rc_signal(i, def_sigquit); 228 break; 229 case SIGTERM: 230 rc_signal(i, def_sigterm); 231 break; 232 default: 233 rc_signal(i, SIG_DFL); 234 } 235 } 236 if (streq(name, "sigexit")) 237 runexit = FALSE; 238 delete_fn(name); 239 } 240 241 extern void whatare_all_signals() { 242 int i; 243 for (i = 1; i < NUMOFSIGNALS; i++) 244 if (*signals[i].name != '\0') { 245 if (sighandlers[i] == SIG_IGN) 246 fprint(1, "fn %s {}\n", signals[i].name); 247 else if (sighandlers[i] == fn_handler) 248 fprint(1, "fn %S {%T}\n", signals[i].name, handlers[i]); 249 else 250 fprint(1, "fn %s\n", signals[i].name); 251 } 252 } 253 254 extern void prettyprint_fn(int fd, char *name, Node *n) { 255 fprint(fd, "fn %S {%T}\n", name, n); 256 }