github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/lib9/notify.c (about) 1 // +build !windows 2 3 /* 4 Plan 9 from User Space src/lib9/notify.c 5 http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c 6 7 Copyright 2001-2007 Russ Cox. All Rights Reserved. 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 */ 27 28 /* 29 * Signal handling for Plan 9 programs. 30 * We stubbornly use the strings from Plan 9 instead 31 * of the enumerated Unix constants. 32 * There are some weird translations. In particular, 33 * a "kill" note is the same as SIGTERM in Unix. 34 * There is no equivalent note to Unix's SIGKILL, since 35 * it's not a deliverable signal anyway. 36 * 37 * We do not handle SIGABRT or SIGSEGV, mainly because 38 * the thread library queues its notes for later, and we want 39 * to dump core with the state at time of delivery. 40 * 41 * We have to add some extra entry points to provide the 42 * ability to tweak which signals are deliverable and which 43 * are acted upon. Notifydisable and notifyenable play with 44 * the process signal mask. Notifyignore enables the signal 45 * but will not call notifyf when it comes in. This is occasionally 46 * useful. 47 */ 48 49 #include <u.h> 50 #include <signal.h> 51 #define NOPLAN9DEFINES 52 #include <libc.h> 53 54 extern char *_p9sigstr(int, char*); 55 extern int _p9strsig(char*); 56 57 typedef struct Sig Sig; 58 struct Sig 59 { 60 int sig; /* signal number */ 61 int flags; 62 }; 63 64 enum 65 { 66 Restart = 1<<0, 67 Ignore = 1<<1 68 }; 69 70 static Sig sigs[] = { 71 SIGHUP, 0, 72 SIGINT, 0, 73 SIGQUIT, 0, 74 SIGILL, 0, 75 SIGTRAP, 0, 76 /* SIGABRT, 0, */ 77 #ifdef SIGEMT 78 SIGEMT, 0, 79 #endif 80 SIGFPE, 0, 81 SIGBUS, 0, 82 /* SIGSEGV, 0, */ 83 SIGCHLD, Restart|Ignore, 84 SIGSYS, 0, 85 SIGPIPE, Ignore, 86 SIGALRM, 0, 87 SIGTERM, 0, 88 SIGTSTP, Restart|Ignore, 89 /* SIGTTIN, Restart|Ignore, */ 90 /* SIGTTOU, Restart|Ignore, */ 91 SIGXCPU, 0, 92 SIGXFSZ, 0, 93 SIGVTALRM, 0, 94 SIGUSR1, 0, 95 SIGUSR2, 0, 96 #ifdef SIGWINCH 97 SIGWINCH, Restart|Ignore, 98 #endif 99 #ifdef SIGINFO 100 SIGINFO, Restart|Ignore, 101 #endif 102 }; 103 104 static Sig* 105 findsig(int s) 106 { 107 int i; 108 109 for(i=0; i<nelem(sigs); i++) 110 if(sigs[i].sig == s) 111 return &sigs[i]; 112 return nil; 113 } 114 115 /* 116 * The thread library initializes _notejmpbuf to its own 117 * routine which provides a per-pthread jump buffer. 118 * If we're not using the thread library, we assume we are 119 * single-threaded. 120 */ 121 typedef struct Jmp Jmp; 122 struct Jmp 123 { 124 p9jmp_buf b; 125 }; 126 127 static Jmp onejmp; 128 129 static Jmp* 130 getonejmp(void) 131 { 132 return &onejmp; 133 } 134 135 Jmp *(*_notejmpbuf)(void) = getonejmp; 136 static void noteinit(void); 137 138 /* 139 * Actual signal handler. 140 */ 141 142 static void (*notifyf)(void*, char*); /* Plan 9 handler */ 143 144 static void 145 signotify(int sig) 146 { 147 char tmp[64]; 148 Jmp *j; 149 Sig *s; 150 151 j = (*_notejmpbuf)(); 152 switch(p9setjmp(j->b)){ 153 case 0: 154 if(notifyf) 155 (*notifyf)(nil, _p9sigstr(sig, tmp)); 156 /* fall through */ 157 case 1: /* noted(NDFLT) */ 158 if(0)print("DEFAULT %d\n", sig); 159 s = findsig(sig); 160 if(s && (s->flags&Ignore)) 161 return; 162 signal(sig, SIG_DFL); 163 raise(sig); 164 _exit(1); 165 case 2: /* noted(NCONT) */ 166 if(0)print("HANDLED %d\n", sig); 167 return; 168 } 169 } 170 171 static void 172 signonotify(int sig) 173 { 174 USED(sig); 175 } 176 177 int 178 noted(int v) 179 { 180 p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1); 181 abort(); 182 return 0; 183 } 184 185 int 186 notify(void (*f)(void*, char*)) 187 { 188 static int init; 189 190 notifyf = f; 191 if(!init){ 192 init = 1; 193 noteinit(); 194 } 195 return 0; 196 } 197 198 /* 199 * Nonsense about enabling and disabling signals. 200 */ 201 typedef void Sighandler(int); 202 static Sighandler* 203 handler(int s) 204 { 205 struct sigaction sa; 206 207 sigaction(s, nil, &sa); 208 return sa.sa_handler; 209 } 210 211 static int 212 notesetenable(int sig, int enabled) 213 { 214 sigset_t mask, omask; 215 216 if(sig == 0) 217 return -1; 218 219 sigemptyset(&mask); 220 sigaddset(&mask, sig); 221 sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask); 222 return !sigismember(&omask, sig); 223 } 224 225 int 226 noteenable(char *msg) 227 { 228 return notesetenable(_p9strsig(msg), 1); 229 } 230 231 int 232 notedisable(char *msg) 233 { 234 return notesetenable(_p9strsig(msg), 0); 235 } 236 237 static int 238 notifyseton(int s, int on) 239 { 240 Sig *sig; 241 struct sigaction sa, osa; 242 243 sig = findsig(s); 244 if(sig == nil) 245 return -1; 246 memset(&sa, 0, sizeof sa); 247 sa.sa_handler = on ? signotify : signonotify; 248 if(sig->flags&Restart) 249 sa.sa_flags |= SA_RESTART; 250 251 /* 252 * We can't allow signals within signals because there's 253 * only one jump buffer. 254 */ 255 sigfillset(&sa.sa_mask); 256 257 /* 258 * Install handler. 259 */ 260 sigaction(sig->sig, &sa, &osa); 261 return osa.sa_handler == signotify; 262 } 263 264 int 265 notifyon(char *msg) 266 { 267 return notifyseton(_p9strsig(msg), 1); 268 } 269 270 int 271 notifyoff(char *msg) 272 { 273 return notifyseton(_p9strsig(msg), 0); 274 } 275 276 /* 277 * Initialization follows sigs table. 278 */ 279 static void 280 noteinit(void) 281 { 282 int i; 283 Sig *sig; 284 285 for(i=0; i<nelem(sigs); i++){ 286 sig = &sigs[i]; 287 /* 288 * If someone has already installed a handler, 289 * It's probably some ld preload nonsense, 290 * like pct (a SIGVTALRM-based profiler). 291 * Or maybe someone has already called notifyon/notifyoff. 292 * Leave it alone. 293 */ 294 if(handler(sig->sig) != SIG_DFL) 295 continue; 296 notifyseton(sig->sig, 1); 297 } 298 } 299