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