Beispiel #1
0
/*
 * Called at library initialization to set up signal handling.
 * All we really do is initialize the sig_lock rwlocks.
 * All signal handlers are either SIG_DFL or SIG_IGN on exec().
 * However, if any signal handlers were established on alternate
 * link maps before the primary link map has been initialized,
 * then inform the kernel of the new sigacthandler.
 */
void
signal_init()
{
	uberdata_t *udp = curthread->ul_uberdata;
	struct sigaction *sap;
	struct sigaction act;
	rwlock_t *rwlp;
	int sig;

	for (sig = 0; sig < NSIG; sig++) {
		rwlp = &udp->siguaction[sig].sig_lock;
		rwlp->rwlock_magic = RWL_MAGIC;
		rwlp->mutex.mutex_flag = LOCK_INITED;
		rwlp->mutex.mutex_magic = MUTEX_MAGIC;
		sap = &udp->siguaction[sig].sig_uaction;
		if (sap->sa_sigaction != SIG_DFL &&
		    sap->sa_sigaction != SIG_IGN &&
		    __sigaction(sig, NULL, &act) == 0 &&
		    act.sa_sigaction != SIG_DFL &&
		    act.sa_sigaction != SIG_IGN) {
			act = *sap;
			act.sa_flags &= ~SA_NODEFER;
			act.sa_sigaction = udp->sigacthandler;
			act.sa_mask = maskset;
			(void) __sigaction(sig, &act, NULL);
		}
	}
}
Beispiel #2
0
/* If INTERRUPT is nonzero, make signal SIG interrupt system calls
   (causing them to fail with EINTR); if INTERRUPT is zero, make system
   calls be restarted after signal SIG.  */
int
siginterrupt (int sig, int interrupt)
{
#ifdef	SA_RESTART
  extern sigset_t _sigintr attribute_hidden;	/* Defined in signal.c.  */
  struct sigaction action;

  if (__sigaction (sig, (struct sigaction *) NULL, &action) < 0)
    return -1;

  if (interrupt)
    {
      __sigaddset (&_sigintr, sig);
      action.sa_flags &= ~SA_RESTART;
    }
  else
    {
      __sigdelset (&_sigintr, sig);
      action.sa_flags |= SA_RESTART;
    }

  if (__sigaction (sig, &action, (struct sigaction *) NULL) < 0)
    return -1;

  return 0;
#else
  __set_errno (ENOSYS);
  return -1;
#endif
}
Beispiel #3
0
int
__sigaction_beos(int signal, const struct sigaction_beos* beosAction,
	struct sigaction_beos* beosOldAction)
{
	// convert the new action
	struct sigaction action;
	if (beosAction != NULL) {
		action.sa_handler = beosAction->sa_handler;
		action.sa_mask = from_beos_sigset(beosAction->sa_mask);
		action.sa_flags = beosAction->sa_flags | SA_BEOS_COMPATIBLE_HANDLER;
		action.sa_userdata = beosAction->sa_userdata;
	}

	struct sigaction oldAction;
	if (__sigaction(signal, beosAction != NULL ? &action : NULL,
			beosOldAction != NULL ? &oldAction : NULL) != 0) {
		return -1;
	}

	// If the signal is SIGSEGV, set the same signal action for SIGBUS. Those
	// constants had the same value under BeOS.
	if (beosAction != NULL && signal == SIGSEGV)
		__sigaction(SIGBUS, &action, NULL);

	// convert the old action back
	if (beosOldAction != NULL) {
		beosOldAction->sa_handler = oldAction.sa_handler;
		beosOldAction->sa_mask = to_beos_sigset(oldAction.sa_mask);
		beosOldAction->sa_flags
			= oldAction.sa_flags & ~(int)SA_BEOS_COMPATIBLE_HANDLER;
		beosOldAction->sa_userdata = oldAction.sa_userdata;
	}

	return 0;
}
Beispiel #4
0
int
__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
{
  struct sigaction act;
  struct itimerval timer;
#ifndef IS_IN_rtld
  static struct sigaction oact;
  static struct itimerval otimer;
# define oact_ptr &oact
# define otimer_ptr &otimer

  if (sample_buffer == NULL)
    {
      /* Disable profiling.  */
      if (samples == NULL)
	/* Wasn't turned on.  */
	return 0;

      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0)
	return -1;
      samples = NULL;
      return __sigaction (SIGPROF, &oact, NULL);
    }

 if (samples)
    {
      /* Was already turned on.  Restore old timer and signal handler
	 first.  */
      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0
	  || __sigaction (SIGPROF, &oact, NULL) < 0)
	return -1;
    }
#else
 /* In ld.so profiling should never be disabled once it runs.  */
 //assert (sample_buffer != NULL);
# define oact_ptr NULL
# define otimer_ptr NULL
#endif

  samples = sample_buffer;
  nsamples = size / sizeof *samples;
  pc_offset = offset;
  pc_scale = scale;

  act.sa_handler = (sighandler_t) &profil_counter;
  act.sa_flags = SA_RESTART;
  __sigfillset (&act.sa_mask);
  if (__sigaction (SIGPROF, &act, oact_ptr) < 0)
    return -1;

  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = 1000000 / __profile_frequency ();
  timer.it_interval = timer.it_value;
  return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
}
Beispiel #5
0
static int
do_sigwait (const sigset_t *set, int *sig)
{
  sigset_t tmp_mask;
  struct sigaction saved[NSIG];
  struct sigaction action;
  int save_errno;
  int this;

  /* Prepare set.  */
  __sigfillset (&tmp_mask);

  /* Unblock all signals in the SET and register our nice handler.  */
  action.sa_handler = ignore_signal;
  action.sa_flags = 0;
  __sigfillset (&action.sa_mask);	/* Block all signals for handler.  */

  /* Make sure we recognize error conditions by setting WAS_SIG to a
     value which does not describe a legal signal number.  */
  was_sig = -1;

  for (this = 1; this < NSIG; ++this)
    if (__sigismember (set, this))
      {
	/* Unblock this signal.  */
	__sigdelset (&tmp_mask, this);

	/* Register temporary action handler.  */
	if (__sigaction (this, &action, &saved[this]) != 0)
	  goto restore_handler;
      }

  /* Now we can wait for signals.  */
  __sigsuspend (&tmp_mask);

 restore_handler:
  save_errno = errno;

  while (--this >= 1)
    if (__sigismember (set, this))
      /* We ignore errors here since we must restore all handlers.  */
      __sigaction (this, &saved[this], NULL);

  __set_errno (save_errno);

  /* Store the result and return.  */
  *sig = was_sig;
  return was_sig == -1 ? -1 : 0;
}
Beispiel #6
0
static int
perform_flag_actions(spawn_attr_t *sap)
{
	int sig;
	struct sigaction action;

	if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
		(void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
	}

	if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
		(void) memset(&action, 0, sizeof (action));
		action.sa_handler = SIG_IGN;
		for (sig = 1; sig < NSIG; sig++) {
			if (sigismember(&sap->sa_sigignore, sig))
				(void) __sigaction(sig, &action, NULL);
		}
	}

	if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
		(void) memset(&action, 0, sizeof (action));
		action.sa_handler = SIG_DFL;
		for (sig = 1; sig < NSIG; sig++) {
			if (sigismember(&sap->sa_sigdefault, sig))
				(void) __sigaction(sig, &action, NULL);
		}
	}

	if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
		if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
			return (errno);
	}

	if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
		if (setpgid(0, sap->sa_pgroup) != 0)
			return (errno);
	}

	if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
		if (setparam(P_LWPID, P_MYID,
		    sap->sa_schedpolicy, sap->sa_priority) == -1)
			return (errno);
	} else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
		if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
			return (errno);
	}

	return (0);
}
Beispiel #7
0
static void
Abort(const char *msg)
{
	ulwp_t *self;
	struct sigaction act;
	sigset_t sigmask;
	lwpid_t lwpid;

	/* to help with core file debugging */
	panicstr = msg;
	if ((self = __curthread()) != NULL) {
		panic_thread = self;
		lwpid = self->ul_lwpid;
	} else {
		lwpid = _lwp_self();
	}

	/* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
	(void) memset(&act, 0, sizeof (act));
	act.sa_sigaction = SIG_DFL;
	(void) __sigaction(SIGABRT, &act, NULL);

	/* delete SIGABRT from the signal mask */
	(void) sigemptyset(&sigmask);
	(void) sigaddset(&sigmask, SIGABRT);
	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask);

	(void) _lwp_kill(lwpid, SIGABRT);	/* never returns */
	(void) kill(getpid(), SIGABRT);	/* if it does, try harder */
	_exit(127);
}
Beispiel #8
0
/* The cancellation handler.  */
static void
cancel_handler (void *arg)
{
  pid_t child = *(pid_t *) arg;

  INTERNAL_SYSCALL_DECL (err);
  INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);

  TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0));

  DO_LOCK ();

  if (SUB_REF () == 0)
    {
      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
    }

  DO_UNLOCK ();
}
Beispiel #9
0
int
siginterrupt (int sig, int flag)
{
  struct sigaction sa;

  if (sig < 1 || sig >= NSIG) {
    errno = EINVAL;
    return -1;
  }

  if (__sigaction (sig, (struct sigaction *)0, &sa))
    return -1;
 
  if (flag) {
    if (sa.sa_flags & SA_INTERRUPT) return 0;
    sa.sa_flags |= SA_INTERRUPT;
  }
  else {
    if (!(sa.sa_flags & SA_INTERRUPT)) return 0;
    sa.sa_flags &= ~ SA_INTERRUPT;
  }
  return __sigaction (sig, &sa, (struct sigaction *)0);
}
Beispiel #10
0
static void
cancel_handler (void *ptr)
{
#ifndef NO_SIGPIPE
    /* Restore the old signal handler.  */
    struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;

    if (clarg != NULL && clarg->oldaction != NULL)
        __sigaction (SIGPIPE, clarg->oldaction, NULL);
#endif

    /* Free the lock.  */
    __libc_lock_unlock (syslog_lock);
}
Beispiel #11
0
/*
 * take_deferred_signal() is called when ul_critical and ul_sigdefer become
 * zero and a deferred signal has been recorded on the current thread.
 * We are out of the critical region and are ready to take a signal.
 * The kernel has all signals blocked on this lwp, but our value of
 * ul_sigmask is the correct signal mask for the previous context.
 *
 * We call __sigresend() to atomically restore the signal mask and
 * cause the signal to be sent again with the remembered siginfo.
 * We will not return successfully from __sigresend() until the
 * application's signal handler has been run via sigacthandler().
 */
void
take_deferred_signal(int sig)
{
	extern int __sigresend(int, siginfo_t *, sigset_t *);
	ulwp_t *self = curthread;
	siguaction_t *suap = &self->ul_uberdata->siguaction[sig];
	siginfo_t *sip;
	int error;

	ASSERT((self->ul_critical | self->ul_sigdefer | self->ul_cursig) == 0);

	/*
	 * If the signal handler was established with SA_RESETHAND,
	 * the kernel has reset the handler to SIG_DFL, so we have
	 * to reestablish the handler now so that it will be entered
	 * again when we call __sigresend(), below.
	 *
	 * Logically, we should acquire and release the signal's
	 * sig_lock around this operation to protect the integrity
	 * of the signal action while we copy it, as is done below
	 * in _libc_sigaction().  However, we may be on a user-level
	 * sleep queue at this point and lrw_wrlock(&suap->sig_lock)
	 * might attempt to sleep on a different sleep queue and
	 * that would corrupt the entire sleep queue mechanism.
	 *
	 * If we are on a sleep queue we will remove ourself from
	 * it in call_user_handler(), called from sigacthandler(),
	 * before entering the application's signal handler.
	 * In the meantime, we must not acquire any locks.
	 */
	if (suap->sig_uaction.sa_flags & SA_RESETHAND) {
		struct sigaction tact = suap->sig_uaction;
		tact.sa_flags &= ~SA_NODEFER;
		tact.sa_sigaction = self->ul_uberdata->sigacthandler;
		tact.sa_mask = maskset;
		(void) __sigaction(sig, &tact, NULL);
	}

	if (self->ul_siginfo.si_signo == 0)
		sip = NULL;
	else
		sip = &self->ul_siginfo;

	/* EAGAIN can happen only for a pending SIGSTOP signal */
	while ((error = __sigresend(sig, sip, &self->ul_sigmask)) == EAGAIN)
		continue;
	if (error)
		thr_panic("take_deferred_signal(): __sigresend() failed");
}
Beispiel #12
0
static void
cancel_handler(void *ptr) {
#ifndef NO_SIGPIPE
    /* Restore the old signal handler.  */
    struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;

    if (clarg != NULL && clarg->oldaction != NULL)
        __sigaction(SIGPIPE, clarg->oldaction, NULL);
#endif

    if (clarg != NULL && clarg->buf != NULL) {
      free(clarg->buf);
      clarg->buf = NULL;
    }
    
    /* Free the lock.  */
    pthread_mutex_unlock(&syslogex_lock);
}
Beispiel #13
0
int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) {
  // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
  // so we have to use sigaction(2) rather than rt_sigaction(2).
  struct sigaction kernel_new_action;
  if (bionic_new_action != NULL) {
    kernel_new_action.sa_flags = bionic_new_action->sa_flags;
    kernel_new_action.sa_handler = bionic_new_action->sa_handler;
    kernel_new_action.sa_mask = bionic_new_action->sa_mask;
#if defined(SA_RESTORER)
    kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;

    if (!(kernel_new_action.sa_flags & SA_RESTORER)) {
      kernel_new_action.sa_flags |= SA_RESTORER;
      kernel_new_action.sa_restorer = (kernel_new_action.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
    }
#endif
  }
  return __sigaction(signal, (bionic_new_action != NULL) ? &kernel_new_action : NULL, bionic_old_action);
}
Beispiel #14
0
/*
 * Set up the SIGCANCEL handler for threads cancellation,
 * needed only when we have more than one thread,
 * or the SIGAIOCANCEL handler for aio cancellation,
 * called when aio is initialized, in __uaio_init().
 */
void
setup_cancelsig(int sig)
{
	uberdata_t *udp = curthread->ul_uberdata;
	rwlock_t *rwlp = &udp->siguaction[sig].sig_lock;
	struct sigaction act;

	ASSERT(sig == SIGCANCEL || sig == SIGAIOCANCEL);
	lrw_rdlock(rwlp);
	act = udp->siguaction[sig].sig_uaction;
	lrw_unlock(rwlp);
	if (act.sa_sigaction == SIG_DFL ||
	    act.sa_sigaction == SIG_IGN)
		act.sa_flags = SA_SIGINFO;
	else {
		act.sa_flags |= SA_SIGINFO;
		act.sa_flags &= ~(SA_NODEFER | SA_RESETHAND | SA_RESTART);
	}
	act.sa_sigaction = udp->sigacthandler;
	act.sa_mask = maskset;
	(void) __sigaction(sig, &act, NULL);
}
Beispiel #15
0
int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) {
#if __LP64__
  __kernel_sigaction kernel_new_action;
  if (bionic_new_action != NULL) {
    kernel_new_action.sa_flags = bionic_new_action->sa_flags;
    kernel_new_action.sa_handler = bionic_new_action->sa_handler;
    kernel_new_action.sa_mask = bionic_new_action->sa_mask;
    kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;

    if (!(kernel_new_action.sa_flags & SA_RESTORER)) {
      kernel_new_action.sa_flags |= SA_RESTORER;
      kernel_new_action.sa_restorer = &__rt_sigreturn;
    }
  }

  __kernel_sigaction kernel_old_action;
  int result = __rt_sigaction(signal,
                              (bionic_new_action != NULL) ? &kernel_new_action : NULL,
                              (bionic_old_action != NULL) ? &kernel_old_action : NULL,
                              sizeof(sigset_t));

  if (bionic_old_action != NULL) {
    bionic_old_action->sa_flags = kernel_old_action.sa_flags;
    bionic_old_action->sa_handler = kernel_old_action.sa_handler;
    bionic_old_action->sa_mask = kernel_old_action.sa_mask;
    bionic_old_action->sa_restorer = kernel_old_action.sa_restorer;

    if (bionic_old_action->sa_restorer == &__rt_sigreturn) {
      bionic_old_action->sa_flags &= ~SA_RESTORER;
    }
  }

  return result;
#else
  // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t.
  // TODO: if we also had correct struct sigaction definitions available, we could copy in and out.
  return __sigaction(signal, bionic_new_action, bionic_old_action);
#endif
}
Beispiel #16
0
/* Set the handler for the signal SIG to HANDLER,
   returning the old handler, or SIG_ERR on error.  */
__sighandler_t
__sysv_signal (int sig, __sighandler_t handler)
{
  struct sigaction act, oact;

  /* Check signal extents to protect __sigismember.  */
  if (handler == SIG_ERR || sig < 1 || sig >= NSIG)
    {
      __set_errno (EINVAL);
      return SIG_ERR;
    }

  act.sa_handler = handler;
  if (__sigemptyset (&act.sa_mask) < 0)
    return SIG_ERR;
  act.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
  act.sa_flags &= ~SA_RESTART;
  if (__sigaction (sig, &act, &oact) < 0)
    return SIG_ERR;

  return oact.sa_handler;
}
int
sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
{
    return __sigaction(sig, act, oact);
}
Beispiel #18
0
int
sigaction(int sig, const struct sigaction *nact, struct sigaction *oact)
{
	ulwp_t *self = curthread;
	uberdata_t *udp = self->ul_uberdata;
	struct sigaction oaction;
	struct sigaction tact;
	struct sigaction *tactp = NULL;
	int rv;

	if (sig <= 0 || sig >= NSIG) {
		errno = EINVAL;
		return (-1);
	}

	if (!self->ul_vfork)
		lrw_wrlock(&udp->siguaction[sig].sig_lock);

	oaction = udp->siguaction[sig].sig_uaction;

	if (nact != NULL) {
		tact = *nact;	/* make a copy so we can modify it */
		tactp = &tact;
		delete_reserved_signals(&tact.sa_mask);

#if !defined(_LP64)
		tact.sa_resv[0] = tact.sa_resv[1] = 0;	/* cleanliness */
#endif
		/*
		 * To be compatible with the behavior of SunOS 4.x:
		 * If the new signal handler is SIG_IGN or SIG_DFL, do
		 * not change the signal's entry in the siguaction array.
		 * This allows a child of vfork(2) to set signal handlers
		 * to SIG_IGN or SIG_DFL without affecting the parent.
		 *
		 * This also covers a race condition with some thread
		 * setting the signal action to SIG_DFL or SIG_IGN
		 * when the thread has also received and deferred
		 * that signal.  When the thread takes the deferred
		 * signal, even though it has set the action to SIG_DFL
		 * or SIG_IGN, it will execute the old signal handler
		 * anyway.  This is an inherent signaling race condition
		 * and is not a bug.
		 *
		 * A child of vfork() is not allowed to change signal
		 * handlers to anything other than SIG_DFL or SIG_IGN.
		 */
		if (self->ul_vfork) {
			if (tact.sa_sigaction != SIG_IGN)
				tact.sa_sigaction = SIG_DFL;
		} else if (sig == SIGCANCEL || sig == SIGAIOCANCEL) {
			/*
			 * Always catch these signals.
			 * We need SIGCANCEL for pthread_cancel() to work.
			 * We need SIGAIOCANCEL for aio_cancel() to work.
			 */
			udp->siguaction[sig].sig_uaction = tact;
			if (tact.sa_sigaction == SIG_DFL ||
			    tact.sa_sigaction == SIG_IGN)
				tact.sa_flags = SA_SIGINFO;
			else {
				tact.sa_flags |= SA_SIGINFO;
				tact.sa_flags &=
				    ~(SA_NODEFER | SA_RESETHAND | SA_RESTART);
			}
			tact.sa_sigaction = udp->sigacthandler;
			tact.sa_mask = maskset;
		} else if (tact.sa_sigaction != SIG_DFL &&
		    tact.sa_sigaction != SIG_IGN) {
			udp->siguaction[sig].sig_uaction = tact;
			tact.sa_flags &= ~SA_NODEFER;
			tact.sa_sigaction = udp->sigacthandler;
			tact.sa_mask = maskset;
		}
	}

	if ((rv = __sigaction(sig, tactp, oact)) != 0)
		udp->siguaction[sig].sig_uaction = oaction;
	else if (oact != NULL &&
	    oact->sa_sigaction != SIG_DFL &&
	    oact->sa_sigaction != SIG_IGN)
		*oact = oaction;

	/*
	 * We detect setting the disposition of SIGIO just to set the
	 * _sigio_enabled flag for the asynchronous i/o (aio) code.
	 */
	if (sig == SIGIO && rv == 0 && tactp != NULL) {
		_sigio_enabled =
		    (tactp->sa_handler != SIG_DFL &&
		    tactp->sa_handler != SIG_IGN);
	}

	if (!self->ul_vfork)
		lrw_unlock(&udp->siguaction[sig].sig_lock);
	return (rv);
}
Beispiel #19
0
void
__vsyslog_chk(int pri, int flag, const char *fmt, va_list ap)
{
    struct tm now_tm;
    time_t now;
    int fd;
    FILE *f;
    char *buf = 0;
    size_t bufsize = 0;
    size_t msgoff;
#ifndef NO_SIGPIPE
    struct sigaction action, oldaction;
    int sigpipe;
#endif
    int saved_errno = errno;
    char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"];

#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
    /* Check for invalid bits. */
    if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
        syslog(INTERNALLOG,
               "syslog: unknown facility/priority: %x", pri);
        pri &= LOG_PRIMASK|LOG_FACMASK;
    }

    /* Check priority against setlogmask values. */
    if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
        return;

    /* Set default facility if none specified. */
    if ((pri & LOG_FACMASK) == 0)
        pri |= LogFacility;

    /* Build the message in a memory-buffer stream.  */
    f = __open_memstream (&buf, &bufsize);
    if (f == NULL)
    {
        /* We cannot get a stream.  There is not much we can do but
           emitting an error messages.  */
        char numbuf[3 * sizeof (pid_t)];
        char *nump;
        char *endp = __stpcpy (failbuf, "out of memory [");
        pid_t pid = __getpid ();

        nump = numbuf + sizeof (numbuf);
        /* The PID can never be zero.  */
        do
            *--nump = '0' + pid % 10;
        while ((pid /= 10) != 0);

        endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump);
        *endp++ = ']';
        *endp = '\0';
        buf = failbuf;
        bufsize = endp - failbuf;
        msgoff = 0;
    }
    else
    {
        __fsetlocking (f, FSETLOCKING_BYCALLER);
        fprintf (f, "<%d>", pri);
        (void) time (&now);
        f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr,
                                          f->_IO_write_end
                                          - f->_IO_write_ptr,
                                          "%h %e %T ",
                                          __localtime_r (&now, &now_tm),
                                          _nl_C_locobj_ptr);
        msgoff = ftell (f);
        if (LogTag == NULL)
            LogTag = __progname;
        if (LogTag != NULL)
            __fputs_unlocked (LogTag, f);
        if (LogStat & LOG_PID)
            fprintf (f, "[%d]", (int) __getpid ());
        if (LogTag != NULL)
        {
            putc_unlocked (':', f);
            putc_unlocked (' ', f);
        }

        /* Restore errno for %m format.  */
        __set_errno (saved_errno);

        /* We have the header.  Print the user's format into the
               buffer.  */
        if (flag == -1)
            vfprintf (f, fmt, ap);
        else
            __vfprintf_chk (f, flag, fmt, ap);

        /* Close the memory stream; this will finalize the data
           into a malloc'd buffer in BUF.  */
        fclose (f);
    }

    /* Output to stderr if requested. */
    if (LogStat & LOG_PERROR) {
        struct iovec iov[2];
        struct iovec *v = iov;

        v->iov_base = buf + msgoff;
        v->iov_len = bufsize - msgoff;
        /* Append a newline if necessary.  */
        if (buf[bufsize - 1] != '\n')
        {
            ++v;
            v->iov_base = (char *) "\n";
            v->iov_len = 1;
        }

        __libc_cleanup_push (free, buf == failbuf ? NULL : buf);

        /* writev is a cancellation point.  */
        (void)__writev(STDERR_FILENO, iov, v - iov + 1);

        __libc_cleanup_pop (0);
    }

    /* Prepare for multiple users.  We have to take care: open and
       write are cancellation points.  */
    struct cleanup_arg clarg;
    clarg.buf = buf;
    clarg.oldaction = NULL;
    __libc_cleanup_push (cancel_handler, &clarg);
    __libc_lock_lock (syslog_lock);

#ifndef NO_SIGPIPE
    /* Prepare for a broken connection.  */
    memset (&action, 0, sizeof (action));
    action.sa_handler = sigpipe_handler;
    sigemptyset (&action.sa_mask);
    sigpipe = __sigaction (SIGPIPE, &action, &oldaction);
    if (sigpipe == 0)
        clarg.oldaction = &oldaction;
#endif

    /* Get connected, output the message to the local logger. */
    if (!connected)
        openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);

    /* If we have a SOCK_STREAM connection, also send ASCII NUL as
       a record terminator.  */
    if (LogType == SOCK_STREAM)
        ++bufsize;

    if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
    {
        if (connected)
        {
            /* Try to reopen the syslog connection.  Maybe it went
               down.  */
            closelog_internal ();
            openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
        }

        if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0)
        {
            closelog_internal ();	/* attempt re-open next time */
            /*
             * Output the message to the console; don't worry
             * about blocking, if console blocks everything will.
             * Make sure the error reported is the one from the
             * syslogd failure.
             */
            if (LogStat & LOG_CONS &&
                    (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0)
            {
                __dprintf (fd, "%s\r\n", buf + msgoff);
                (void)__close(fd);
            }
        }
    }

#ifndef NO_SIGPIPE
    if (sigpipe == 0)
        __sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL);
#endif

    /* End of critical section.  */
    __libc_cleanup_pop (0);
    __libc_lock_unlock (syslog_lock);

    if (buf != failbuf)
        free (buf);
}
Beispiel #20
0
/* Execute LINE as a shell command, returning its status.  */
static int
do_system (const char *line)
{
  int status, save;
  pid_t pid;
  struct sigaction sa;
#ifndef _LIBC_REENTRANT
  struct sigaction intr, quit;
#endif
  sigset_t omask;

  sa.sa_handler = SIG_IGN;
  sa.sa_flags = 0;
  __sigemptyset (&sa.sa_mask);

  DO_LOCK ();
  if (ADD_REF () == 0)
    {
      if (__sigaction (SIGINT, &sa, &intr) < 0)
	{
	  (void) SUB_REF ();
	  goto out;
	}
      if (__sigaction (SIGQUIT, &sa, &quit) < 0)
	{
	  save = errno;
	  (void) SUB_REF ();
	  goto out_restore_sigint;
	}
    }
  DO_UNLOCK ();

  /* We reuse the bitmap in the 'sa' structure.  */
  __sigaddset (&sa.sa_mask, SIGCHLD);
  save = errno;
  if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
    {
#ifndef _LIBC
      if (errno == ENOSYS)
	__set_errno (save);
      else
#endif
	{
	  DO_LOCK ();
	  if (SUB_REF () == 0)
	    {
	      save = errno;
	      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
	    out_restore_sigint:
	      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
	      __set_errno (save);
	    }
	out:
	  DO_UNLOCK ();
	  return -1;
	}
    }

#ifdef CLEANUP_HANDLER
  CLEANUP_HANDLER;
#endif

#ifdef FORK
  pid = FORK ();
#else
  pid = __fork ();
#endif
  if (pid == (pid_t) 0)
    {
      /* Child side.  */
      const char *new_argv[4];
      new_argv[0] = SHELL_NAME;
      new_argv[1] = "-c";
      new_argv[2] = line;
      new_argv[3] = NULL;

      /* Restore the signals.  */
      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
      (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
      INIT_LOCK ();

      /* Exec the shell.  */
      (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
      _exit (127);
    }
  else if (pid < (pid_t) 0)
    /* The fork failed.  */
    status = -1;
  else
    /* Parent side.  */
    {
      /* Note the system() is a cancellation point.  But since we call
	 waitpid() which itself is a cancellation point we do not
	 have to do anything here.  */
      if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
	status = -1;
    }

#ifdef CLEANUP_HANDLER
  CLEANUP_RESET;
#endif

  save = errno;
  DO_LOCK ();
  if ((SUB_REF () == 0
       && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
	   | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
      || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
    {
#ifndef _LIBC
      /* glibc cannot be used on systems without waitpid.  */
      if (errno == ENOSYS)
	__set_errno (save);
      else
#endif
	status = -1;
    }
  DO_UNLOCK ();

  return status;
}
Beispiel #21
0
/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
   Before running the process perform the actions described in FILE-ACTIONS. */
int
__spawni (pid_t *pid, const char *file,
	  const posix_spawn_file_actions_t *file_actions,
	  const posix_spawnattr_t *attrp, char *const argv[],
	  char *const envp[], int xflags)
{
  pid_t new_pid;
  char *path, *p, *name;
  size_t len;
  size_t pathlen;

  /* Do this once.  */
  short int flags = attrp == NULL ? 0 : attrp->__flags;

  /* Generate the new process.  */
  if ((flags & POSIX_SPAWN_USEVFORK) != 0
      /* If no major work is done, allow using vfork.  Note that we
	 might perform the path searching.  But this would be done by
	 a call to execvp(), too, and such a call must be OK according
	 to POSIX.  */
      || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
		    | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
		    | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
	  && file_actions == NULL))
    new_pid = __vfork ();
  else
    new_pid = __fork ();

  if (new_pid != 0)
    {
      if (new_pid < 0)
	return errno;

      /* The call was successful.  Store the PID if necessary.  */
      if (pid != NULL)
	*pid = new_pid;

      return 0;
    }

  /* Set signal mask.  */
  if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
      && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0)
    _exit (SPAWN_ERROR);

  /* Set signal default action.  */
  if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
    {
      /* We have to iterate over all signals.  This could possibly be
	 done better but it requires system specific solutions since
	 the sigset_t data type can be very different on different
	 architectures.  */
      int sig;
      struct sigaction sa;

      memset (&sa, '\0', sizeof (sa));
      sa.sa_handler = SIG_DFL;

      for (sig = 1; sig <= _NSIG; ++sig)
	if (__sigismember (&attrp->__sd, sig) != 0
	    && __sigaction (sig, &sa, NULL) != 0)
	  _exit (SPAWN_ERROR);

    }

#ifdef _POSIX_PRIORITY_SCHEDULING
  /* Set the scheduling algorithm and parameters.  */
  if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
      == POSIX_SPAWN_SETSCHEDPARAM)
    {
      if (__sched_setparam (0, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
  else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
    {
      if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
#endif

  /* Set the process group ID.  */
  if ((flags & POSIX_SPAWN_SETPGROUP) != 0
      && __setpgid (0, attrp->__pgrp) != 0)
    _exit (SPAWN_ERROR);

  /* Set the effective user and group IDs.  */
  if ((flags & POSIX_SPAWN_RESETIDS) != 0
      && (local_seteuid (__getuid ()) != 0
	  || local_setegid (__getgid ()) != 0))
    _exit (SPAWN_ERROR);

  /* Execute the file actions.  */
  if (file_actions != NULL)
    {
      int cnt;
      struct rlimit64 fdlimit;
      bool have_fdlimit = false;

      for (cnt = 0; cnt < file_actions->__used; ++cnt)
	{
	  struct __spawn_action *action = &file_actions->__actions[cnt];

	  switch (action->tag)
	    {
	    case spawn_do_close:
	      if (close_not_cancel (action->action.close_action.fd) != 0)
		{
		  if (! have_fdlimit)
		    {
		      getrlimit64 (RLIMIT_NOFILE, &fdlimit);
		      have_fdlimit = true;
		    }

		  /* Only signal errors for file descriptors out of range.  */
		  if (action->action.close_action.fd < 0
		      || action->action.close_action.fd >= fdlimit.rlim_cur)
		    /* Signal the error.  */
		    _exit (SPAWN_ERROR);
		}
	      break;

	    case spawn_do_open:
	      {
		int new_fd = open_not_cancel (action->action.open_action.path,
					      action->action.open_action.oflag
					      | O_LARGEFILE,
					      action->action.open_action.mode);

		if (new_fd == -1)
		  /* The `open' call failed.  */
		  _exit (SPAWN_ERROR);

		/* Make sure the desired file descriptor is used.  */
		if (new_fd != action->action.open_action.fd)
		  {
		    if (__dup2 (new_fd, action->action.open_action.fd)
			!= action->action.open_action.fd)
		      /* The `dup2' call failed.  */
		      _exit (SPAWN_ERROR);

		    if (close_not_cancel (new_fd) != 0)
		      /* The `close' call failed.  */
		      _exit (SPAWN_ERROR);
		  }
	      }
	      break;

	    case spawn_do_dup2:
	      if (__dup2 (action->action.dup2_action.fd,
			  action->action.dup2_action.newfd)
		  != action->action.dup2_action.newfd)
		/* The `dup2' call failed.  */
		_exit (SPAWN_ERROR);
	      break;
	    }
	}
    }

  if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL)
    {
      /* The FILE parameter is actually a path.  */
      __execve (file, argv, envp);

      maybe_script_execute (file, argv, envp, xflags);

      /* Oh, oh.  `execve' returns.  This is bad.  */
      _exit (SPAWN_ERROR);
    }

  /* We have to search for FILE on the path.  */
  path = getenv ("PATH");
  if (path == NULL)
    {
      /* There is no `PATH' in the environment.
	 The default search path is the current directory
	 followed by the path `confstr' returns for `_CS_PATH'.  */
      len = confstr (_CS_PATH, (char *) NULL, 0);
      path = (char *) __alloca (1 + len);
      path[0] = ':';
      (void) confstr (_CS_PATH, path + 1, len);
    }

  len = strlen (file) + 1;
  pathlen = strlen (path);
  name = __alloca (pathlen + len + 1);
  /* Copy the file name at the top.  */
  name = (char *) memcpy (name + pathlen + 1, file, len);
  /* And add the slash.  */
  *--name = '/';

  p = path;
  do
    {
      char *startp;

      path = p;
      p = __strchrnul (path, ':');

      if (p == path)
	/* Two adjacent colons, or a colon at the beginning or the end
	   of `PATH' means to search the current directory.  */
	startp = name + 1;
      else
	startp = (char *) memcpy (name - (p - path), path, p - path);

      /* Try to execute this name.  If it works, execv will not return.  */
      __execve (startp, argv, envp);

      maybe_script_execute (startp, argv, envp, xflags);

      switch (errno)
	{
	case EACCES:
	case ENOENT:
	case ESTALE:
	case ENOTDIR:
	  /* Those errors indicate the file is missing or not executable
	     by us, in which case we want to just try the next path
	     directory.  */
	  break;

	default:
	  /* Some other error means we found an executable file, but
	     something went wrong executing it; return the error to our
	     caller.  */
	  _exit (SPAWN_ERROR);
	    }
    }
  while (*p++ != '\0');

  /* Return with an error.  */
  _exit (SPAWN_ERROR);
}
Beispiel #22
0
/* We are going to use the `nanosleep' syscall of the kernel.  But the
   kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
   behaviour for this syscall.  Therefore we have to emulate it here.  */
unsigned int
__sleep (unsigned int seconds)
{
  const unsigned int max
    = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
  struct timespec ts;
  sigset_t set, oset;
  unsigned int result;

  /* This is not necessary but some buggy programs depend on this.  */
  if (__glibc_unlikely (seconds == 0))
    {
#ifdef CANCELLATION_P
      CANCELLATION_P (THREAD_SELF);
#endif
      return 0;
    }

  ts.tv_sec = 0;
  ts.tv_nsec = 0;
 again:
  if (sizeof (ts.tv_sec) <= sizeof (seconds))
    {
      /* Since SECONDS is unsigned assigning the value to .tv_sec can
	 overflow it.  In this case we have to wait in steps.  */
      ts.tv_sec += MIN (seconds, max);
      seconds -= (unsigned int) ts.tv_sec;
    }
  else
    {
      ts.tv_sec = (time_t) seconds;
      seconds = 0;
    }

  /* Linux will wake up the system call, nanosleep, when SIGCHLD
     arrives even if SIGCHLD is ignored.  We have to deal with it
     in libc.  We block SIGCHLD first.  */
  __sigemptyset (&set);
  __sigaddset (&set, SIGCHLD);
  if (__sigprocmask (SIG_BLOCK, &set, &oset))
    return -1;

  /* If SIGCHLD is already blocked, we don't have to do anything.  */
  if (!__sigismember (&oset, SIGCHLD))
    {
      int saved_errno;
      struct sigaction oact;

      __sigemptyset (&set);
      __sigaddset (&set, SIGCHLD);

      /* We get the signal handler for SIGCHLD.  */
      if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
	{
	  saved_errno = errno;
	  /* Restore the original signal mask.  */
	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	  __set_errno (saved_errno);
	  return -1;
	}

      /* Note the sleep() is a cancellation point.  But since we call
	 nanosleep() which itself is a cancellation point we do not
	 have to do anything here.  */
      if (oact.sa_handler == SIG_IGN)
	{
	  //__libc_cleanup_push (cl, &oset);

	  /* We should leave SIGCHLD blocked.  */
	  while (1)
	    {
	      result = __nanosleep (&ts, &ts);

	      if (result != 0 || seconds == 0)
		break;

	      if (sizeof (ts.tv_sec) <= sizeof (seconds))
		{
		  ts.tv_sec = MIN (seconds, max);
		  seconds -= (unsigned int) ts.tv_nsec;
		}
	    }

	  //__libc_cleanup_pop (0);

	  saved_errno = errno;
	  /* Restore the original signal mask.  */
	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	  __set_errno (saved_errno);

	  goto out;
	}

      /* We should unblock SIGCHLD.  Restore the original signal mask.  */
      (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
    }

  result = __nanosleep (&ts, &ts);
  if (result == 0 && seconds != 0)
    goto again;

 out:
  if (result != 0)
    /* Round remaining time.  */
    result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);

  return result;
}
Beispiel #23
0
/* Cause an abnormal program termination with core-dump.  */
void
abort (void)
{
  struct sigaction act;
  sigset_t sigs;

  /* First acquire the lock.  */
  __libc_lock_lock_recursive (lock);

  /* Now it's for sure we are alone.  But recursive calls are possible.  */

  /* Unlock SIGABRT.  */
  if (stage == 0)
    {
      ++stage;
      if (__sigemptyset (&sigs) == 0 &&
	  __sigaddset (&sigs, SIGABRT) == 0)
	__sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
    }

  /* Flush all streams.  We cannot close them now because the user
     might have registered a handler for SIGABRT.  */
  if (stage == 1)
    {
      ++stage;
      fflush (NULL);
    }

  /* Send signal which possibly calls a user handler.  */
  if (stage == 2)
    {
      /* This stage is special: we must allow repeated calls of
	 `abort' when a user defined handler for SIGABRT is installed.
	 This is risky since the `raise' implementation might also
	 fail but I don't see another possibility.  */
      int save_stage = stage;

      stage = 0;
      __libc_lock_unlock_recursive (lock);

      raise (SIGABRT);

      __libc_lock_lock_recursive (lock);
      stage = save_stage + 1;
    }

  /* There was a handler installed.  Now remove it.  */
  if (stage == 3)
    {
      ++stage;
      memset (&act, '\0', sizeof (struct sigaction));
      act.sa_handler = SIG_DFL;
      __sigfillset (&act.sa_mask);
      act.sa_flags = 0;
      __sigaction (SIGABRT, &act, NULL);
    }

  /* Now close the streams which also flushes the output the user
     defined handler might has produced.  */
  if (stage == 4)
    {
      ++stage;
      __fcloseall ();
    }

  /* Try again.  */
  if (stage == 5)
    {
      ++stage;
      raise (SIGABRT);
    }

  /* Now try to abort using the system specific command.  */
  if (stage == 6)
    {
      ++stage;
      ABORT_INSTRUCTION;
    }

  /* If we can't signal ourselves and the abort instruction failed, exit.  */
  if (stage == 7)
    {
      ++stage;
      _exit (127);
    }

  /* If even this fails try to use the provided instruction to crash
     or otherwise make sure we never return.  */
  while (1)
    /* Try for ever and ever.  */
    ABORT_INSTRUCTION;
}
Beispiel #24
0
/* Set the disposition for SIG.  */
__sighandler_t
sigset (int sig, __sighandler_t disp)
{
  struct sigaction act;
  struct sigaction oact;
  sigset_t set;
  sigset_t oset;

#ifdef SIG_HOLD
  /* Handle SIG_HOLD first.  */
  if (disp == SIG_HOLD)
    {
      /* Create an empty signal set.  */
      if (__sigemptyset (&set) < 0)
	return SIG_ERR;

      /* Add the specified signal.  */
      if (__sigaddset (&set, sig) < 0)
	return SIG_ERR;

      /* Add the signal set to the current signal mask.  */
      if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0)
	return SIG_ERR;

      /* If the signal was already blocked signal this to the caller.  */
      if (__sigismember (&oset, sig))
	return SIG_HOLD;

      /* We need to determine whether a specific handler is installed.  */
      if (__sigaction (sig, NULL, &oact) < 0)
	return SIG_ERR;

      return oact.sa_handler;
    }
#endif	/* SIG_HOLD */

  /* Check signal extents to protect __sigismember.  */
  if (disp == SIG_ERR || sig < 1 || sig >= NSIG)
    {
      __set_errno (EINVAL);
      return SIG_ERR;
    }

  act.sa_handler = disp;
  if (__sigemptyset (&act.sa_mask) < 0)
    return SIG_ERR;
  act.sa_flags = 0;
  if (__sigaction (sig, &act, &oact) < 0)
    return SIG_ERR;

  /* Create an empty signal set.  */
  if (__sigemptyset (&set) < 0)
    return SIG_ERR;

  /* Add the specified signal.  */
  if (__sigaddset (&set, sig) < 0)
    return SIG_ERR;

  /* Remove the signal set from the current signal mask.  */
  if (__sigprocmask (SIG_UNBLOCK, &set, &oset) < 0)
    return SIG_ERR;

  /* If the signal was already blocked return SIG_HOLD.  */
  return __sigismember (&oset, sig) ? SIG_HOLD : oact.sa_handler;
}
Beispiel #25
0
static void
__vsyslogex_chk(int pri, int flag, pid_t cpid, pid_t ctid, const char *fmt, va_list ap) {
    struct tm now_tm;
    time_t now;
    int fd;
    FILE *f;
    char *buf = 0;
    size_t bufsize = 0;
    size_t prioff, msgoff;
#ifndef NO_SIGPIPE
    struct sigaction action, oldaction;
    int sigpipe;
#endif
    int saved_errno = errno;
    char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"];
    const int LogMask = setlogmask(0);

#ifdef _DEBUGFLAGS_H_
    {
        static unsigned int registered = 0;
        if (unlikely(0 == registered)) {
            registered = 1; /* dirty work around to avoid deadlock: syslogex->register->syslogex */
            registered = (registerLibraryDebugFlags(&debugFlags) == EXIT_SUCCESS);
        }
    }
#endif /*_DEBUGFLAGS_H_*/

#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
    /* Check for invalid bits. */
    if (unlikely(pri & ~(LOG_PRIMASK | LOG_FACMASK))) {
        /*syslog(INTERNALLOG,
               "syslog: unknown facility/priority: %x", pri);*/
        WARNING_MSG("unknown facility/priority: %x", pri);
        pri &= LOG_PRIMASK | LOG_FACMASK;
    }

    /* Check priority against setlogmask values. */
    if (unlikely((LOG_MASK(LOG_PRI(pri)) & LogMask) == 0))
        return;

    /* Set default facility if none specified. */
    if (unlikely((pri & LOG_FACMASK) == 0))
        pri |= LogFacility;

    /* Build the message in a memory-buffer stream.  */
    f = open_memstream(&buf, &bufsize);
    if (unlikely(f == NULL)) {
        /* We cannot get a stream.  There is not much we can do but
           emitting an error messages with the Process ID.  */
        char numbuf[3 * sizeof (pid_t)];
        char *nump;
        char *endp = __stpcpy(failbuf, "out of memory [");
        pid_t pid = getpid();

        nump = numbuf + sizeof (numbuf);
        /* The PID can never be zero.  */
        do {
            *--nump = '0' + pid % 10;
        } while ((pid /= 10) != 0);

        endp = mempcpy((void*) endp, (const void*) nump, (size_t) ((numbuf + sizeof (numbuf)) - nump));
        *endp++ = ']';
        *endp = '\0';
        buf = failbuf;
        bufsize = endp - failbuf;
        msgoff = 0;
    } else {
        __fsetlocking(f, FSETLOCKING_BYCALLER);
        prioff = fprintf(f, "<%d>", pri);
        (void) time(&now);
        f->_IO_write_ptr += strftime(f->_IO_write_ptr,
                f->_IO_write_end - f->_IO_write_ptr,
                "%h %e %T ",
                localtime_r(&now, &now_tm));
        /*f->_IO_write_ptr += strftime_l (f->_IO_write_ptr,
                                          f->_IO_write_end - f->_IO_write_ptr,
                                          "%h %e %T ",
                                          localtime_r (&now, &now_tm));*/
        msgoff = ftell(f);
        if (LogTag == NULL)
            LogTag = __progname;
        if (LogTag != NULL)
            fputs_unlocked(LogTag, f);
        if (LogStat & LOG_PID) {
            const pid_t pid = ((0 == cpid) ? getpid() : cpid);
            if (LogStat & LOG_TID) {
                const pid_t tid = ((0 == ctid) ? gettid() : ctid);
                fprintf(f, "[%d:%d]", (int) pid, (int) tid);
            } else {
                fprintf(f, "[%d]", (int) pid);
            }
        }

        if (LogStat & LOG_RDTSC) {
            const unsigned long long int t = rdtsc();
            fprintf(f, "(%llu)", t);
        } /* (LogStat & LOG_RDTSC) */

        if (LogStat & LOG_CLOCK) {
            #if HAVE_CLOCK_GETTIME
                struct timespec timeStamp;
                if (clock_gettime(CLOCK_MONOTONIC,&timeStamp) == 0) {
                    fprintf(f,"(%lu.%.9d)",timeStamp.tv_sec,timeStamp.tv_nsec);
                } else {
                    const int error = errno;
                    ERROR_MSG("clock_gettime CLOCK_MONOTONIC error %d (%m)",error);
            }
            #else
                static unsigned int alreadyPrinted = 0;
                if (unlikely(0 == alreadyPrinted)) {
                    ERROR_MSG("clock_gettime  not available on this system");
                    alreadyPrinted = 1;
                }
            #endif
        }  /* (LogStat & LOG_CLOCK) */

        if (LogStat & LOG_LEVEL) {
            switch (LOG_PRI(pri)) {
                case LOG_EMERG:
                    fprintf(f, "[EMERG]");
                    break;
                case LOG_ALERT:
                    fprintf(f, "[ALERT]");
                    break;
                case LOG_CRIT:
                    fprintf(f, "[CRIT]");
                    break;
                case LOG_ERR:
                    fprintf(f, "[ERROR]");
                    break;
                case LOG_WARNING:
                    fprintf(f, "[WARNING]");
                    break;
                case LOG_NOTICE:
                    fprintf(f, "[NOTICE]");
                    break;
                case LOG_INFO:
                    fprintf(f, "[INFO]");
                    break;
                case LOG_DEBUG:
                    fprintf(f, "[DEBUG]");
                    break;
            } /* switch(LOG_PRI(pri))*/
        } /* (LogStat & LOG_LEVEL) */

        if (LogTag != NULL) {
            putc_unlocked(':', f);
            putc_unlocked(' ', f);
        }

        /* Restore errno for %m format.  */
        __set_errno(saved_errno);

        /* We have the header.  Print the user's format into the
         buffer.  */
        if (flag == -1) {
            vfprintf(f, fmt, ap);
        } else {
            __vfprintf_chk(f, flag, fmt, ap);
        }

        /* Close the memory stream; this will finalize the data
           into a malloc'd buffer in BUF.  */
        fclose(f);
    }

    /* Output to stderr if requested. */
    if (LogStat & LOG_PERROR) {
        struct iovec iov[2];
        register struct iovec *v = iov;

        v->iov_base = buf + msgoff;
        v->iov_len = bufsize - msgoff;
        /* Append a newline if necessary.  */
        if (buf[bufsize - 1] != '\n') {
            ++v;
            v->iov_base = (char *) "\n";
            v->iov_len = 1;
        }

        pthread_cleanup_push(free, buf == failbuf ? NULL : buf);

        /* writev is a cancellation point.  */
        (void) writev(STDERR_FILENO, iov, v - iov + 1);

        pthread_cleanup_pop(0);
    }

    /* Prepare for multiple users.  We have to take care: open and
  write are cancellation points.  */
    struct cleanup_arg clarg;
    clarg.buf = buf;
    clarg.oldaction = NULL;
    pthread_cleanup_push(cancel_handler, &clarg);
    pthread_mutex_lock(&syslogex_lock);

#ifndef NO_SIGPIPE
    /* Prepare for a broken connection.  */
    memset(&action, 0, sizeof (action));
    action.sa_handler = sigpipe_handler;
    sigemptyset(&action.sa_mask);
    sigpipe = __sigaction(SIGPIPE, &action, &oldaction);
    if (sigpipe == 0)
        clarg.oldaction = &oldaction;
#endif

    /* Get connected, output the message to the local logger. */
    if (!connected) {
        openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
    }

    /* If we have a SOCK_STREAM connection, also send ASCII NUL as
  a record terminator.  */
    if (LogType == SOCK_STREAM) {
        ++bufsize;
    }

    if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) {
        if (connected) {
            /* Try to reopen the syslog connection.  Maybe it went
          down.  */
            closelog_internal();
            openlog_internal(LogTag, LogStat | LOG_NDELAY, 0);
        }

        if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) {
            closelog_internal(); /* attempt re-open next time */
            /*
             * Output the message to the console; don't worry
             * about blocking, if console blocks everything will.
             * Make sure the error reported is the one from the
             * syslogd failure.
             */
            if (LogStat & LOG_CONS &&
                    (fd = __open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY, 0)) >= 0) {
                dprintf(fd, "%s\r\n", buf + msgoff);
                (void) __close(fd);
            }
        }
    }

#ifndef NO_SIGPIPE
    if (sigpipe == 0)
        __sigaction(SIGPIPE, &oldaction, (struct sigaction *) NULL);
#endif

    /* End of critical section.  */
    pthread_cleanup_pop(0);
    pthread_mutex_unlock(&syslogex_lock);

    if (buf != failbuf) {
        free(buf);
    }
}
Beispiel #26
0
int
__lckpwdf (void)
{
  int flags;
  sigset_t saved_set;			/* Saved set of caught signals.  */
  struct sigaction saved_act;		/* Saved signal action.  */
  sigset_t new_set;			/* New set of caught signals.  */
  struct sigaction new_act;		/* New signal action.  */
  struct flock fl;			/* Information struct for locking.  */
  int result;

  if (lock_fd != -1)
    /* Still locked by own process.  */
    return -1;

  /* Prevent problems caused by multiple threads.  */
  __libc_lock_lock (lock);

  int oflags = O_WRONLY | O_CREAT;
#ifdef O_CLOEXEC
  oflags |= O_CLOEXEC;
#endif
  lock_fd = __open (PWD_LOCKFILE, oflags, 0600);
  if (lock_fd == -1)
    /* Cannot create lock file.  */
    RETURN_CLOSE_FD (-1);

#ifndef __ASSUME_O_CLOEXEC
# ifdef O_CLOEXEC
  if (__have_o_cloexec <= 0)
# endif
    {
      /* Make sure file gets correctly closed when process finished.  */
      flags = __fcntl (lock_fd, F_GETFD, 0);
      if (flags == -1)
	/* Cannot get file flags.  */
	RETURN_CLOSE_FD (-1);
# ifdef O_CLOEXEC
      if (__have_o_cloexec == 0)
	__have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
      if (__have_o_cloexec < 0)
# endif
	{
	  flags |= FD_CLOEXEC;		/* Close on exit.  */
	  if (__fcntl (lock_fd, F_SETFD, flags) < 0)
	    /* Cannot set new flags.  */
	    RETURN_CLOSE_FD (-1);
	}
    }
#endif

  /* Now we have to get exclusive write access.  Since multiple
     process could try this we won't stop when it first fails.
     Instead we set a timeout for the system call.  Once the timer
     expires it is likely that there are some problems which cannot be
     resolved by waiting.

     It is important that we don't change the signal state.  We must
     restore the old signal behaviour.  */
  memset (&new_act, '\0', sizeof (struct sigaction));
  new_act.sa_handler = noop_handler;
  __sigfillset (&new_act.sa_mask);
  new_act.sa_flags = 0ul;

  /* Install new action handler for alarm and save old.  */
  if (__sigaction (SIGALRM, &new_act, &saved_act) < 0)
    /* Cannot install signal handler.  */
    RETURN_CLOSE_FD (-1);

  /* Now make sure the alarm signal is not blocked.  */
  __sigemptyset (&new_set);
  __sigaddset (&new_set, SIGALRM);
  if (__sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
    RETURN_RESTORE_HANDLER (-1);

  /* Start timer.  If we cannot get the lock in the specified time we
     get a signal.  */
  alarm (TIMEOUT);

  /* Try to get the lock.  */
  memset (&fl, '\0', sizeof (struct flock));
  fl.l_type = F_WRLCK;
  fl.l_whence = SEEK_SET;
  result = __fcntl (lock_fd, F_SETLKW, &fl);

  RETURN_CLEAR_ALARM (result);
}