summaryrefslogtreecommitdiff
path: root/dotfiles/system/.zsh/modules/Src/signals.c
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-01-26 17:36:38 -0600
committerCraig Jennings <c@cjennings.net>2026-01-26 17:36:38 -0600
commitdada2f255daaa2fb493ec8c7d47e2a8123aea494 (patch)
tree0c0eeb84bb7b6e66a2d7f41cdfd061b25f80cc14 /dotfiles/system/.zsh/modules/Src/signals.c
parentd50e5955837788fc69b4d5bc74cb574b859ed31a (diff)
refactor(dotfiles): rename system/ to common/ and remove unused configs
Rename dotfiles/system to dotfiles/common for clarity - indicates shared dotfiles used across all desktop environments (DWM, Hyprland). Removed config directories for uninstalled applications: - ghostty (using different terminal) - lf (using ranger instead) - mopidy (using mpd instead) - nitrogen (X11-only, obsolete for Wayland) - pychess (not installed) - JetBrains (not installed via archsetup) - youtube-dl (using yt-dlp with different config location) Kept audacious config for potential future use. Updated all references in archsetup, CLAUDE.md, todo.org, and validation.sh. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'dotfiles/system/.zsh/modules/Src/signals.c')
-rw-r--r--dotfiles/system/.zsh/modules/Src/signals.c1479
1 files changed, 0 insertions, 1479 deletions
diff --git a/dotfiles/system/.zsh/modules/Src/signals.c b/dotfiles/system/.zsh/modules/Src/signals.c
deleted file mode 100644
index 20c6fdf..0000000
--- a/dotfiles/system/.zsh/modules/Src/signals.c
+++ /dev/null
@@ -1,1479 +0,0 @@
-/*
- * signals.c - signals handling code
- *
- * This file is part of zsh, the Z shell.
- *
- * Copyright (c) 1992-1997 Paul Falstad
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and to distribute modified versions of this software for any
- * purpose, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * In no event shall Paul Falstad or the Zsh Development Group be liable
- * to any party for direct, indirect, special, incidental, or consequential
- * damages arising out of the use of this software and its documentation,
- * even if Paul Falstad and the Zsh Development Group have been advised of
- * the possibility of such damage.
- *
- * Paul Falstad and the Zsh Development Group specifically disclaim any
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose. The software
- * provided hereunder is on an "as is" basis, and Paul Falstad and the
- * Zsh Development Group have no obligation to provide maintenance,
- * support, updates, enhancements, or modifications.
- *
- */
-
-#include "zsh.mdh"
-#include "signals.pro"
-
-/* Array describing the state of each signal: an element contains *
- * 0 for the default action or some ZSIG_* flags ored together. */
-
-/**/
-mod_export int sigtrapped[VSIGCOUNT];
-
-/*
- * Trap programme lists for each signal.
- *
- * If (sigtrapped[sig] & ZSIG_FUNC) is set, this isn't used.
- * The corresponding shell function is used instead.
- *
- * Otherwise, if sigtrapped[sig] is not zero, this is NULL when a signal
- * is to be ignored, and if not NULL contains the programme list to be
- * eval'd.
- */
-
-/**/
-mod_export Eprog siglists[VSIGCOUNT];
-
-/* Total count of trapped signals */
-
-/**/
-mod_export int nsigtrapped;
-
-/* Running an exit trap? */
-
-/**/
-int in_exit_trap;
-
-/*
- * Flag that exit trap has been set in POSIX mode.
- * The setter's expectation is therefore that it is run
- * on programme exit, not function exit.
- */
-
-/**/
-static int exit_trap_posix;
-
-/* Variables used by signal queueing */
-
-/**/
-mod_export int queueing_enabled, queue_front, queue_rear;
-/**/
-mod_export int signal_queue[MAX_QUEUE_SIZE];
-/**/
-mod_export sigset_t signal_mask_queue[MAX_QUEUE_SIZE];
-#ifdef DEBUG
-/**/
-mod_export int queue_in;
-#endif
-
-/* Variables used by trap queueing */
-
-/**/
-mod_export int trap_queueing_enabled, trap_queue_front, trap_queue_rear;
-/**/
-mod_export int trap_queue[MAX_QUEUE_SIZE];
-
-/* This is only used on machines that don't understand signal sets. *
- * On SYSV machines this will represent the signals that are blocked *
- * (held) using sighold. On machines which can't block signals at *
- * all, we will simulate this by ignoring them and remembering them *
- * in this variable. */
-#if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
-static sigset_t blocked_set;
-#endif
-
-#ifdef POSIX_SIGNALS
-# define signal_jmp_buf sigjmp_buf
-# define signal_setjmp(b) sigsetjmp((b),1)
-# define signal_longjmp(b,n) siglongjmp((b),(n))
-#else
-# define signal_jmp_buf jmp_buf
-# define signal_setjmp(b) setjmp(b)
-# define signal_longjmp(b,n) longjmp((b),(n))
-#endif
-
-#ifdef NO_SIGNAL_BLOCKING
-# define signal_process(sig) signal_ignore(sig)
-# define signal_reset(sig) install_handler(sig)
-#else
-# define signal_process(sig) ;
-# define signal_reset(sig) ;
-#endif
-
-/* Install signal handler for given signal. *
- * If possible, we want to make sure that interrupted *
- * system calls are not restarted. */
-
-/**/
-mod_export void
-install_handler(int sig)
-{
-#ifdef POSIX_SIGNALS
- struct sigaction act;
-
- act.sa_handler = (SIGNAL_HANDTYPE) zhandler;
- sigemptyset(&act.sa_mask); /* only block sig while in handler */
- act.sa_flags = 0;
-# ifdef SA_INTERRUPT /* SunOS 4.x */
- if (interact)
- act.sa_flags |= SA_INTERRUPT; /* make sure system calls are not restarted */
-# endif
- sigaction(sig, &act, (struct sigaction *)NULL);
-#else
-# ifdef BSD_SIGNALS
- struct sigvec vec;
-
- vec.sv_handler = (SIGNAL_HANDTYPE) zhandler;
- vec.sv_mask = sigmask(sig); /* mask out this signal while in handler */
-# ifdef SV_INTERRUPT
- vec.sv_flags = SV_INTERRUPT; /* make sure system calls are not restarted */
-# endif
- sigvec(sig, &vec, (struct sigvec *)NULL);
-# else
-# ifdef SYSV_SIGNALS
- /* we want sigset rather than signal because it will *
- * block sig while in handler. signal usually doesn't */
- sigset(sig, zhandler);
-# else /* NO_SIGNAL_BLOCKING (bummer) */
- signal(sig, zhandler);
-
-# endif /* SYSV_SIGNALS */
-# endif /* BSD_SIGNALS */
-#endif /* POSIX_SIGNALS */
-}
-
-/* enable ^C interrupts */
-
-/**/
-mod_export void
-intr(void)
-{
- if (interact)
- install_handler(SIGINT);
-}
-
-/* disable ^C interrupts */
-
-#if 0 /**/
-void
-nointr(void)
-{
- if (interact)
- signal_ignore(SIGINT);
-}
-#endif
-
-/* temporarily block ^C interrupts */
-
-/**/
-mod_export void
-holdintr(void)
-{
- if (interact)
- signal_block(signal_mask(SIGINT));
-}
-
-/* release ^C interrupts */
-
-/**/
-mod_export void
-noholdintr(void)
-{
- if (interact)
- signal_unblock(signal_mask(SIGINT));
-}
-
-/* create a signal mask containing *
- * only the given signal */
-
-/**/
-mod_export sigset_t
-signal_mask(int sig)
-{
- sigset_t set;
-
- sigemptyset(&set);
- if (sig)
- sigaddset(&set, sig);
- return set;
-}
-
-/* Block the signals in the given signal *
- * set. Return the old signal set. */
-
-/**/
-#ifndef BSD_SIGNALS
-
-/**/
-mod_export sigset_t
-signal_block(sigset_t set)
-{
- sigset_t oset;
-
-#ifdef POSIX_SIGNALS
- sigprocmask(SIG_BLOCK, &set, &oset);
-
-#else
-# ifdef SYSV_SIGNALS
- int i;
-
- oset = blocked_set;
- for (i = 1; i <= NSIG; ++i) {
- if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
- sigaddset(&blocked_set, i);
- sighold(i);
- }
- }
-# else /* NO_SIGNAL_BLOCKING */
-/* We will just ignore signals if the system doesn't have *
- * the ability to block them. */
- int i;
-
- oset = blocked_set;
- for (i = 1; i <= NSIG; ++i) {
- if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
- sigaddset(&blocked_set, i);
- signal_ignore(i);
- }
- }
-# endif /* SYSV_SIGNALS */
-#endif /* POSIX_SIGNALS */
-
- return oset;
-}
-
-/**/
-#endif /* BSD_SIGNALS */
-
-/* Unblock the signals in the given signal *
- * set. Return the old signal set. */
-
-/**/
-mod_export sigset_t
-signal_unblock(sigset_t set)
-{
- sigset_t oset;
-
-#ifdef POSIX_SIGNALS
- sigprocmask(SIG_UNBLOCK, &set, &oset);
-#else
-# ifdef BSD_SIGNALS
- sigfillset(&oset);
- oset = sigsetmask(oset);
- sigsetmask(oset & ~set);
-# else
-# ifdef SYSV_SIGNALS
- int i;
-
- oset = blocked_set;
- for (i = 1; i <= NSIG; ++i) {
- if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
- sigdelset(&blocked_set, i);
- sigrelse(i);
- }
- }
-# else /* NO_SIGNAL_BLOCKING */
-/* On systems that can't block signals, we are just ignoring them. So *
- * to unblock signals, we just reenable the signal handler for them. */
- int i;
-
- oset = blocked_set;
- for (i = 1; i <= NSIG; ++i) {
- if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
- sigdelset(&blocked_set, i);
- install_handler(i);
- }
- }
-# endif /* SYSV_SIGNALS */
-# endif /* BSD_SIGNALS */
-#endif /* POSIX_SIGNALS */
-
- return oset;
-}
-
-/* set the process signal mask to *
- * be the given signal mask */
-
-/**/
-mod_export sigset_t
-signal_setmask(sigset_t set)
-{
- sigset_t oset;
-
-#ifdef POSIX_SIGNALS
- sigprocmask(SIG_SETMASK, &set, &oset);
-#else
-# ifdef BSD_SIGNALS
- oset = sigsetmask(set);
-# else
-# ifdef SYSV_SIGNALS
- int i;
-
- oset = blocked_set;
- for (i = 1; i <= NSIG; ++i) {
- if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
- sigaddset(&blocked_set, i);
- sighold(i);
- } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
- sigdelset(&blocked_set, i);
- sigrelse(i);
- }
- }
-# else /* NO_SIGNAL_BLOCKING */
- int i;
-
- oset = blocked_set;
- for (i = 1; i < NSIG; ++i) {
- if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
- sigaddset(&blocked_set, i);
- signal_ignore(i);
- } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
- sigdelset(&blocked_set, i);
- install_handler(i);
- }
- }
-# endif /* SYSV_SIGNALS */
-# endif /* BSD_SIGNALS */
-#endif /* POSIX_SIGNALS */
-
- return oset;
-}
-
-#if defined(NO_SIGNAL_BLOCKING)
-static int suspend_longjmp = 0;
-static signal_jmp_buf suspend_jmp_buf;
-#endif
-
-/**/
-int
-signal_suspend(UNUSED(int sig), int wait_cmd)
-{
- int ret;
-
-#if defined(POSIX_SIGNALS) || defined(BSD_SIGNALS)
- sigset_t set;
-# if defined(POSIX_SIGNALS) && defined(BROKEN_POSIX_SIGSUSPEND)
- sigset_t oset;
-# endif
-
- sigemptyset(&set);
-
- /* SIGINT from the terminal driver needs to interrupt "wait"
- * and to cause traps to fire, but otherwise should not be
- * handled by the shell until after any foreground job has
- * a chance to decide whether to exit on that signal.
- */
- if (!(wait_cmd || isset(TRAPSASYNC) ||
- (sigtrapped[SIGINT] & ~ZSIG_IGNORED)))
- sigaddset(&set, SIGINT);
-#endif /* POSIX_SIGNALS || BSD_SIGNALS */
-
-#ifdef POSIX_SIGNALS
-# ifdef BROKEN_POSIX_SIGSUSPEND
- sigprocmask(SIG_SETMASK, &set, &oset);
- ret = pause();
- sigprocmask(SIG_SETMASK, &oset, NULL);
-# else /* not BROKEN_POSIX_SIGSUSPEND */
- ret = sigsuspend(&set);
-# endif /* BROKEN_POSIX_SIGSUSPEND */
-#else /* not POSIX_SIGNALS */
-# ifdef BSD_SIGNALS
- ret = sigpause(set);
-# else
-# ifdef SYSV_SIGNALS
- ret = sigpause(sig);
-
-# else /* NO_SIGNAL_BLOCKING */
- /* need to use signal_longjmp to make this race-free *
- * between the child_unblock() and pause() */
- if (signal_setjmp(suspend_jmp_buf) == 0) {
- suspend_longjmp = 1; /* we want to signal_longjmp after catching signal */
- child_unblock(); /* do we need to do wait_cmd stuff as well? */
- ret = pause();
- }
- suspend_longjmp = 0; /* turn off using signal_longjmp since we are past *
- * the pause() function. */
-# endif /* SYSV_SIGNALS */
-# endif /* BSD_SIGNALS */
-#endif /* POSIX_SIGNALS */
-
- return ret;
-}
-
-/* last signal we handled: race prone, or what? */
-/**/
-int last_signal;
-
-/*
- * Wait for any processes that have changed state.
- *
- * The main use for this is in the SIGCHLD handler. However,
- * we also use it to pick up status changes of jobs when
- * updating jobs.
- */
-/**/
-void
-wait_for_processes(void)
-{
- /* keep WAITING until no more child processes to reap */
- for (;;) {
- /* save the errno, since WAIT may change it */
- int old_errno = errno;
- int status;
- Job jn;
- Process pn;
- pid_t pid;
- pid_t *procsubpid = &cmdoutpid;
- int *procsubval = &cmdoutval;
- int cont = 0;
- struct execstack *es = exstack;
-
- /*
- * Reap the child process.
- * If we want usage information, we need to use wait3.
- */
-#if defined(HAVE_WAIT3) || defined(HAVE_WAITPID)
-# ifdef WCONTINUED
-# define WAITFLAGS (WNOHANG|WUNTRACED|WCONTINUED)
-# else
-# define WAITFLAGS (WNOHANG|WUNTRACED)
-# endif
-#endif
-#ifdef HAVE_WAIT3
-# ifdef HAVE_GETRUSAGE
- struct rusage ru;
-
- pid = wait3((void *)&status, WAITFLAGS, &ru);
-# else
- pid = wait3((void *)&status, WAITFLAGS, NULL);
-# endif
-#else
-# ifdef HAVE_WAITPID
- pid = waitpid(-1, &status, WAITFLAGS);
-# else
- pid = wait(&status);
-# endif
-#endif
-
- if (!pid) /* no more children to reap */
- break;
-
- /* check if child returned was from process substitution */
- for (;;) {
- if (pid == *procsubpid) {
- *procsubpid = 0;
- if (WIFSIGNALED(status))
- *procsubval = (0200 | WTERMSIG(status));
- else
- *procsubval = WEXITSTATUS(status);
- use_cmdoutval = 1;
- get_usage();
- cont = 1;
- break;
- }
- if (!es)
- break;
- procsubpid = &es->cmdoutpid;
- procsubval = &es->cmdoutval;
- es = es->next;
- }
- if (cont)
- continue;
-
- /* check for WAIT error */
- if (pid == -1) {
- if (errno != ECHILD)
- zerr("wait failed: %e", errno);
- /* WAIT changed errno, so restore the original */
- errno = old_errno;
- break;
- }
-
- /* This is necessary to be sure queueing_enabled > 0 when
- * we enter printjob() from update_job(), so that we don't
- * decrement to zero in should_report_time() and improperly
- * run other handlers in the middle of processing this one */
- queue_signals();
-
- /*
- * Find the process and job containing this pid and
- * update it.
- */
- if (findproc(pid, &jn, &pn, 0)) {
- if (((jn->stat & STAT_BUILTIN) ||
- (list_pipe &&
- (thisjob == -1 ||
- (jobtab[thisjob].stat & STAT_BUILTIN)))) &&
- WIFSTOPPED(status) && WSTOPSIG(status) == SIGTSTP) {
- killjb(jn, SIGCONT);
- zwarn("job can't be suspended");
- } else {
-#if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE)
- struct timezone dummy_tz;
- gettimeofday(&pn->endtime, &dummy_tz);
-#ifdef WIFCONTINUED
- if (WIFCONTINUED(status))
- pn->status = SP_RUNNING;
- else
-#endif
- pn->status = status;
- pn->ti = ru;
-#else
- update_process(pn, status);
-#endif
- if (WIFEXITED(status) &&
- pn->pid == jn->gleader &&
- killpg(pn->pid, 0) == -1) {
- jn->gleader = 0;
- if (!(jn->stat & STAT_NOSTTY)) {
- /*
- * This PID was in control of the terminal;
- * reclaim terminal now it has exited.
- * It's still possible some future forked
- * process of this job will become group
- * leader, however.
- */
- attachtty(mypgrp);
- }
- }
- }
- update_job(jn);
- } else if (findproc(pid, &jn, &pn, 1)) {
- pn->status = status;
- update_job(jn);
- } else {
- /* If not found, update the shell record of time spent by
- * children in sub processes anyway: otherwise, this
- * will get added on to the next found process that
- * terminates.
- */
- get_usage();
- }
- /*
- * Accumulate a list of older jobs. We only do this for
- * background jobs, which is something in the job table
- * that's not marked as in the current shell or as shell builtin
- * and is not equal to the current foreground job.
- */
- if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) &&
- jn - jobtab != thisjob) {
- int val = (WIFSIGNALED(status) ?
- 0200 | WTERMSIG(status) :
- (WIFSTOPPED(status) ?
- 0200 | WEXITSTATUS(status) :
- WEXITSTATUS(status)));
- addbgstatus(pid, val);
- }
-
- unqueue_signals();
- }
-}
-
-/* the signal handler */
-
-/**/
-mod_export void
-zhandler(int sig)
-{
- sigset_t newmask, oldmask;
-
-#if defined(NO_SIGNAL_BLOCKING)
- int do_jump;
- signal_jmp_buf jump_to;
-#endif
-
- last_signal = sig;
- signal_process(sig);
-
- sigfillset(&newmask);
- /* Block all signals temporarily */
- oldmask = signal_block(newmask);
-
-#if defined(NO_SIGNAL_BLOCKING)
- /* do we need to longjmp to signal_suspend */
- do_jump = suspend_longjmp;
- /* In case a SIGCHLD somehow arrives */
- suspend_longjmp = 0;
-
- /* Traps can cause nested signal_suspend() */
- if (sig == SIGCHLD) {
- if (do_jump) {
- /* Copy suspend_jmp_buf */
- jump_to = suspend_jmp_buf;
- }
- }
-#endif
-
- /* Are we queueing signals now? */
- if (queueing_enabled) {
- int temp_rear = ++queue_rear % MAX_QUEUE_SIZE;
-
- DPUTS(temp_rear == queue_front, "BUG: signal queue full");
- /* Make sure it's not full (extremely unlikely) */
- if (temp_rear != queue_front) {
- /* ok, not full, so add to queue */
- queue_rear = temp_rear;
- /* save signal caught */
- signal_queue[queue_rear] = sig;
- /* save current signal mask */
- signal_mask_queue[queue_rear] = oldmask;
- }
- signal_reset(sig);
- return;
- }
-
- /* Reset signal mask, signal traps ok now */
- signal_setmask(oldmask);
-
- switch (sig) {
- case SIGCHLD:
- wait_for_processes();
- break;
-
- case SIGPIPE:
- if (!handletrap(SIGPIPE)) {
- if (!interact)
- _exit(SIGPIPE);
- else if (!isatty(SHTTY)) {
- stopmsg = 1;
- zexit(SIGPIPE, 1);
- }
- }
- break;
-
- case SIGHUP:
- if (!handletrap(SIGHUP)) {
- stopmsg = 1;
- zexit(SIGHUP, 1);
- }
- break;
-
- case SIGINT:
- if (!handletrap(SIGINT)) {
- if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
- isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL))
- zexit(SIGINT, 1);
- if (list_pipe || chline || simple_pline) {
- breaks = loops;
- errflag |= ERRFLAG_INT;
- inerrflush();
- check_cursh_sig(SIGINT);
- }
- lastval = 128 + SIGINT;
- }
- break;
-
-#ifdef SIGWINCH
- case SIGWINCH:
- adjustwinsize(1); /* check window size and adjust */
- (void) handletrap(SIGWINCH);
- break;
-#endif
-
- case SIGALRM:
- if (!handletrap(SIGALRM)) {
- int idle = ttyidlegetfn(NULL);
- int tmout = getiparam("TMOUT");
- if (idle >= 0 && idle < tmout)
- alarm(tmout - idle);
- else {
- /*
- * We want to exit now.
- * Cancel all errors, including a user interrupt
- * which is now redundant.
- */
- errflag = noerrs = 0;
- zwarn("timeout");
- stopmsg = 1;
- zexit(SIGALRM, 1);
- }
- }
- break;
-
- default:
- (void) handletrap(sig);
- break;
- } /* end of switch(sig) */
-
- signal_reset(sig);
-
-/* This is used to make signal_suspend() race-free */
-#if defined(NO_SIGNAL_BLOCKING)
- if (do_jump)
- signal_longjmp(jump_to, 1);
-#endif
-
-} /* handler */
-
-
-/* SIGHUP any jobs left running */
-
-/**/
-void
-killrunjobs(int from_signal)
-{
- int i, killed = 0;
-
- if (unset(HUP))
- return;
- for (i = 1; i <= maxjob; i++)
- if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) &&
- !(jobtab[i].stat & STAT_NOPRINT) &&
- !(jobtab[i].stat & STAT_STOPPED)) {
- if (jobtab[i].gleader != getpid() &&
- killpg(jobtab[i].gleader, SIGHUP) != -1)
- killed++;
- }
- if (killed)
- zwarn("warning: %d jobs SIGHUPed", killed);
-}
-
-
-/* send a signal to a job (simply involves kill if monitoring is on) */
-
-/**/
-int
-killjb(Job jn, int sig)
-{
- Process pn;
- int err = 0;
-
- if (jobbing) {
- if (jn->stat & STAT_SUPERJOB) {
- if (sig == SIGCONT) {
- for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
- if (killpg(pn->pid, sig) == -1)
- if (kill(pn->pid, sig) == -1 && errno != ESRCH)
- err = -1;
-
- /*
- * Note this does not kill the last process,
- * which is assumed to be the one controlling the
- * subjob, i.e. the forked zsh that was originally
- * list_pipe_pid...
- */
- for (pn = jn->procs; pn->next; pn = pn->next)
- if (kill(pn->pid, sig) == -1 && errno != ESRCH)
- err = -1;
-
- /*
- * ...we only continue that once the external processes
- * currently associated with the subjob are finished.
- */
- if (!jobtab[jn->other].procs && pn)
- if (kill(pn->pid, sig) == -1 && errno != ESRCH)
- err = -1;
-
- return err;
- }
- if (killpg(jobtab[jn->other].gleader, sig) == -1 && errno != ESRCH)
- err = -1;
-
- if (killpg(jn->gleader, sig) == -1 && errno != ESRCH)
- err = -1;
-
- return err;
- }
- else
- return killpg(jn->gleader, sig);
- }
- for (pn = jn->procs; pn; pn = pn->next) {
- /*
- * Do not kill this job's process if it's already dead as its
- * pid could have been reused by the system.
- * As the PID doesn't exist don't return an error.
- */
- if (pn->status == SP_RUNNING || WIFSTOPPED(pn->status)) {
- /*
- * kill -0 on a job is pointless. We still call kill() for each process
- * in case the user cares about it but we ignore its outcome.
- */
- if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH && sig != 0)
- return -1;
- }
- }
- return err;
-}
-
-/*
- * List for saving traps. We don't usually have that many traps
- * at once, so just use a linked list.
- */
-struct savetrap {
- int sig, flags, local, posix;
- void *list;
-};
-
-static LinkList savetraps;
-static int dontsavetrap;
-
-/*
- * Save the current trap by copying it. This does nothing to
- * the existing value of sigtrapped or siglists.
- */
-
-static void
-dosavetrap(int sig, int level)
-{
- struct savetrap *st;
- st = (struct savetrap *)zalloc(sizeof(*st));
- st->sig = sig;
- st->local = level;
- st->posix = (sig == SIGEXIT) ? exit_trap_posix : 0;
- if ((st->flags = sigtrapped[sig]) & ZSIG_FUNC) {
- /*
- * Get the old function: this assumes we haven't added
- * the new one yet.
- */
- Shfunc shf, newshf = NULL;
- if ((shf = (Shfunc)gettrapnode(sig, 1))) {
- /* Copy the node for saving */
- newshf = (Shfunc) zshcalloc(sizeof(*newshf));
- newshf->node.nam = ztrdup(shf->node.nam);
- newshf->node.flags = shf->node.flags;
- newshf->funcdef = dupeprog(shf->funcdef, 0);
- if (shf->node.flags & PM_LOADDIR) {
- dircache_set(&newshf->filename, shf->filename);
- } else {
- newshf->filename = ztrdup(shf->filename);
- }
- if (shf->sticky) {
- newshf->sticky = sticky_emulation_dup(shf->sticky, 0);
- } else
- newshf->sticky = 0;
- if (shf->node.flags & PM_UNDEFINED)
- newshf->funcdef->shf = newshf;
- }
-#ifdef DEBUG
- else dputs("BUG: no function present with function trap flag set.");
-#endif
- DPUTS(siglists[sig], "BUG: function signal has eval list, too.");
- st->list = newshf;
- } else if (sigtrapped[sig]) {
- st->list = siglists[sig] ? dupeprog(siglists[sig], 0) : NULL;
- } else {
- DPUTS(siglists[sig], "BUG: siglists not null for untrapped signal");
- st->list = NULL;
- }
- if (!savetraps)
- savetraps = znewlinklist();
- /*
- * Put this at the front of the list
- */
- zinsertlinknode(savetraps, (LinkNode)savetraps, st);
-}
-
-
-/*
- * Set a trap: note this does not handle manipulation of
- * the function table for TRAPNAL functions.
- *
- * sig is the signal number.
- *
- * l is the list to be eval'd for a trap defined with the "trap"
- * builtin and should be NULL for a function trap.
- *
- * flags includes any additional flags to be or'd into sigtrapped[sig],
- * in particular ZSIG_FUNC; the basic flags will be assigned within
- * settrap.
- */
-
-/**/
-mod_export int
-settrap(int sig, Eprog l, int flags)
-{
- if (sig == -1)
- return 1;
- if (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)) {
- zerr("can't trap SIG%s in interactive shells", sigs[sig]);
- return 1;
- }
-
- /*
- * Call unsettrap() unconditionally, to make sure trap is saved
- * if necessary.
- */
- queue_signals();
- unsettrap(sig);
-
- DPUTS((flags & ZSIG_FUNC) && l,
- "BUG: trap function has passed eval list, too");
- siglists[sig] = l;
- if (!(flags & ZSIG_FUNC) && empty_eprog(l)) {
- sigtrapped[sig] = ZSIG_IGNORED;
- if (sig && sig <= SIGCOUNT &&
-#ifdef SIGWINCH
- sig != SIGWINCH &&
-#endif
- sig != SIGCHLD)
- signal_ignore(sig);
- } else {
- nsigtrapped++;
- sigtrapped[sig] = ZSIG_TRAPPED;
- if (sig && sig <= SIGCOUNT &&
-#ifdef SIGWINCH
- sig != SIGWINCH &&
-#endif
- sig != SIGCHLD)
- install_handler(sig);
- }
- sigtrapped[sig] |= flags;
- /*
- * Note that introducing the locallevel does not affect whether
- * sigtrapped[sig] is zero or not, i.e. a test without a mask
- * works just the same.
- */
- if (sig == SIGEXIT) {
- /* Make POSIX behaviour of EXIT trap sticky */
- exit_trap_posix = isset(POSIXTRAPS);
- /* POSIX exit traps are not local. */
- if (!exit_trap_posix)
- sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
- }
- else
- sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
- unqueue_signals();
- return 0;
-}
-
-/**/
-void
-unsettrap(int sig)
-{
- HashNode hn;
-
- queue_signals();
- hn = removetrap(sig);
- if (hn)
- shfunctab->freenode(hn);
- unqueue_signals();
-}
-
-/**/
-HashNode
-removetrap(int sig)
-{
- int trapped;
-
- if (sig == -1 ||
- (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)))
- return NULL;
-
- queue_signals();
- trapped = sigtrapped[sig];
- /*
- * Note that we save the trap here even if there isn't an existing
- * one, to aid in removing this one. However, if there's
- * already one at the current locallevel we just overwrite it.
- *
- * Note we save EXIT traps based on the *current* setting of
- * POSIXTRAPS --- so if there is POSIX EXIT trap set but
- * we are in native mode it can be saved, replaced by a function
- * trap, and then restored.
- */
- if (!dontsavetrap &&
- (sig == SIGEXIT ? !isset(POSIXTRAPS) : isset(LOCALTRAPS)) &&
- locallevel &&
- (!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
- dosavetrap(sig, locallevel);
-
- if (!trapped) {
- unqueue_signals();
- return NULL;
- }
- if (sigtrapped[sig] & ZSIG_TRAPPED)
- nsigtrapped--;
- sigtrapped[sig] = 0;
- if (sig == SIGINT && interact) {
- /* PWS 1995/05/16: added test for interactive, also noholdintr() *
- * as subshells ignoring SIGINT have it blocked from delivery */
- intr();
- noholdintr();
- } else if (sig == SIGHUP)
- install_handler(sig);
- else if (sig == SIGPIPE && interact && !forklevel)
- install_handler(sig);
- else if (sig && sig <= SIGCOUNT &&
-#ifdef SIGWINCH
- sig != SIGWINCH &&
-#endif
- sig != SIGCHLD)
- signal_default(sig);
- if (sig == SIGEXIT)
- exit_trap_posix = 0;
-
- /*
- * At this point we free the appropriate structs. If we don't
- * want that to happen then either the function should already have been
- * removed from shfunctab, or the entry in siglists should have been set
- * to NULL. This is no longer necessary for saving traps as that
- * copies the structures, so here we are remove the originals.
- * That causes a little inefficiency, but a good deal more reliability.
- */
- if (trapped & ZSIG_FUNC) {
- HashNode node = gettrapnode(sig, 1);
-
- /*
- * As in dosavetrap(), don't call removeshfuncnode() because
- * that calls back into unsettrap();
- */
- if (node)
- removehashnode(shfunctab, node->nam);
- unqueue_signals();
-
- return node;
- } else if (siglists[sig]) {
- freeeprog(siglists[sig]);
- siglists[sig] = NULL;
- }
- unqueue_signals();
-
- return NULL;
-}
-
-/**/
-void
-starttrapscope(void)
-{
- /* No special SIGEXIT behaviour inside another trap. */
- if (intrap)
- return;
-
- /*
- * SIGEXIT needs to be restored at the current locallevel,
- * so give it the next higher one. dosavetrap() is called
- * automatically where necessary.
- */
- if (sigtrapped[SIGEXIT] && !exit_trap_posix) {
- locallevel++;
- unsettrap(SIGEXIT);
- locallevel--;
- }
-}
-
-/*
- * Reset traps after the end of a function: must be called after
- * endparamscope() so that the locallevel has been decremented.
- */
-
-/**/
-void
-endtrapscope(void)
-{
- LinkNode ln;
- struct savetrap *st;
- int exittr = 0;
- void *exitfn = NULL;
-
- /*
- * Remember the exit trap, but don't run it until
- * after all the other traps have been put back.
- * Don't do this inside another trap.
- */
- if (!intrap &&
- !exit_trap_posix && (exittr = sigtrapped[SIGEXIT])) {
- if (exittr & ZSIG_FUNC) {
- exitfn = removehashnode(shfunctab, "TRAPEXIT");
- } else {
- exitfn = siglists[SIGEXIT];
- siglists[SIGEXIT] = NULL;
- }
- if (sigtrapped[SIGEXIT] & ZSIG_TRAPPED)
- nsigtrapped--;
- sigtrapped[SIGEXIT] = 0;
- }
-
- if (savetraps) {
- while ((ln = firstnode(savetraps)) &&
- (st = (struct savetrap *) ln->dat) &&
- st->local > locallevel) {
- int sig = st->sig;
-
- remnode(savetraps, ln);
-
- if (st->flags && (st->list != NULL)) {
- /* prevent settrap from saving this */
- dontsavetrap++;
- if (st->flags & ZSIG_FUNC)
- settrap(sig, NULL, ZSIG_FUNC);
- else
- settrap(sig, (Eprog) st->list, 0);
- if (sig == SIGEXIT)
- exit_trap_posix = st->posix;
- dontsavetrap--;
- /*
- * counting of nsigtrapped should presumably be handled
- * in settrap...
- */
- DPUTS((sigtrapped[sig] ^ st->flags) & ZSIG_TRAPPED,
- "BUG: settrap didn't restore correct ZSIG_TRAPPED");
- if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC)
- shfunctab->addnode(shfunctab, ((Shfunc)st->list)->node.nam,
- (Shfunc) st->list);
- } else if (sigtrapped[sig]) {
- /*
- * Don't restore the old state if someone has set a
- * POSIX-style exit trap --- allow this to propagate.
- */
- if (sig != SIGEXIT || !exit_trap_posix)
- unsettrap(sig);
- }
-
- zfree(st, sizeof(*st));
- }
- }
-
- if (exittr) {
- /*
- * We already made sure this wasn't set as a POSIX exit trap.
- * We respect the user's intention when the trap in question
- * was set.
- */
- dotrapargs(SIGEXIT, &exittr, exitfn);
- if (exittr & ZSIG_FUNC)
- shfunctab->freenode((HashNode)exitfn);
- else
- freeeprog(exitfn);
- }
- DPUTS(!locallevel && savetraps && firstnode(savetraps),
- "BUG: still saved traps outside all function scope");
-}
-
-
-/*
- * Decide whether a trap needs handling.
- * If so, see if the trap should be run now or queued.
- * Return 1 if the trap has been or will be handled.
- * This only needs to be called in place of dotrap() in the
- * signal handler, since it's only while waiting for children
- * to exit that we queue traps.
- */
-/**/
-static int
-handletrap(int sig)
-{
- if (!sigtrapped[sig])
- return 0;
-
- if (trap_queueing_enabled)
- {
- /* Code borrowed from signal queueing */
- int temp_rear = ++trap_queue_rear % MAX_QUEUE_SIZE;
-
- DPUTS(temp_rear == trap_queue_front, "BUG: trap queue full");
- /* If queue is not full... */
- if (temp_rear != trap_queue_front) {
- trap_queue_rear = temp_rear;
- trap_queue[trap_queue_rear] = sig;
- }
- return 1;
- }
-
- dotrap(sig);
-
- if (sig == SIGALRM)
- {
- int tmout;
- /*
- * Reset the alarm.
- * It seems slightly more natural to do this when the
- * trap is run, rather than when it's queued, since
- * the user doesn't see the latter.
- */
- if ((tmout = getiparam("TMOUT")))
- alarm(tmout);
- }
-
- return 1;
-}
-
-
-/*
- * Queue traps if they shouldn't be run asynchronously, i.e.
- * we're not in the wait builtin and TRAPSASYNC isn't set, when
- * waiting for children to exit.
- *
- * Note that unlike signal queuing this should only be called
- * in single matching pairs and can't be nested. It is
- * only needed when waiting for a job or process to finish.
- *
- * There is presumably a race setting this up: we shouldn't be running
- * traps between forking a foreground process and this point, either.
- */
-/**/
-void
-queue_traps(int wait_cmd)
-{
- if (!isset(TRAPSASYNC) && !wait_cmd) {
- /*
- * Traps need to be handled synchronously, so
- * enable queueing.
- */
- trap_queueing_enabled = 1;
- }
-}
-
-
-/*
- * Disable trap queuing and run the traps.
- */
-/**/
-void
-unqueue_traps(void)
-{
- trap_queueing_enabled = 0;
- while (trap_queue_front != trap_queue_rear) {
- trap_queue_front = (trap_queue_front + 1) % MAX_QUEUE_SIZE;
- (void) handletrap(trap_queue[trap_queue_front]);
- }
-}
-
-
-/* Execute a trap function for a given signal, possibly
- * with non-standard sigtrapped & siglists values
- */
-
-/* Are we already executing a trap? */
-/**/
-int intrap;
-
-/* Is the current trap a function? */
-
-/**/
-int trapisfunc;
-
-/*
- * If the current trap is not a function, at what function depth
- * did the trap get called?
- */
-/**/
-int traplocallevel;
-
-/*
- * sig is the signal number.
- * *sigtr is the value to be taken as the field in sigtrapped (since
- * that may have changed by this point if we are exiting).
- * sigfn is an Eprog with a non-function eval list, or a Shfunc
- * with a function trap. It may be NULL with an ignored signal.
- */
-
-/**/
-static void
-dotrapargs(int sig, int *sigtr, void *sigfn)
-{
- LinkList args;
- char *name, num[4];
- int obreaks = breaks;
- int oretflag = retflag;
- int olastval = lastval;
- int isfunc;
- int traperr, new_trap_state, new_trap_return;
-
- /* if signal is being ignored or the trap function *
- * is NULL, then return *
- * *
- * Also return if errflag is set. In fact, the code in the *
- * function will test for this, but this way we keep status flags *
- * intact without working too hard. Special cases (e.g. calling *
- * a trap for SIGINT after the error flag was set) are handled *
- * by the calling code. (PWS 1995/06/08). *
- * *
- * This test is now replicated in dotrap(). */
- if ((*sigtr & ZSIG_IGNORED) || !sigfn || errflag)
- return;
-
- /*
- * Never execute special (synchronous) traps inside other traps.
- * This can cause unexpected code execution when more than one
- * of these is set.
- *
- * The down side is that it's harder to debug traps. I don't think
- * that's a big issue.
- */
- if (intrap) {
- switch (sig) {
- case SIGEXIT:
- case SIGDEBUG:
- case SIGZERR:
- return;
- }
- }
-
- queue_signals(); /* Any time we manage memory or global state */
-
- intrap++;
- *sigtr |= ZSIG_IGNORED;
-
- zcontext_save();
- /* execsave will save the old trap_return and trap_state */
- execsave();
- breaks = retflag = 0;
- traplocallevel = locallevel;
- runhookdef(BEFORETRAPHOOK, NULL);
- if (*sigtr & ZSIG_FUNC) {
- int osc = sfcontext, old_incompfunc = incompfunc;
- HashNode hn = gettrapnode(sig, 0);
-
- args = znewlinklist();
- /*
- * In case of multiple names, try to get
- * a hint of the name in use from the function table.
- * In special cases, e.g. EXIT traps, the function
- * has already been removed. Then it's OK to
- * use the standard name.
- */
- if (hn) {
- name = ztrdup(hn->nam);
- } else {
- name = (char *) zalloc(5 + strlen(sigs[sig]));
- sprintf(name, "TRAP%s", sigs[sig]);
- }
- zaddlinknode(args, name);
- sprintf(num, "%d", sig);
- zaddlinknode(args, num);
-
- trap_return = -1; /* incremented by doshfunc */
- trap_state = TRAP_STATE_PRIMED;
- trapisfunc = isfunc = 1;
-
- sfcontext = SFC_SIGNAL;
- incompfunc = 0;
- doshfunc((Shfunc)sigfn, args, 1); /* manages signal queueing */
- sfcontext = osc;
- incompfunc= old_incompfunc;
- freelinklist(args, (FreeFunc) NULL);
- zsfree(name);
- } else {
- trap_return = -2; /* not incremented, used at current level */
- trap_state = TRAP_STATE_PRIMED;
- trapisfunc = isfunc = 0;
-
- execode((Eprog)sigfn, 1, 0, "trap"); /* manages signal queueing */
- }
- runhookdef(AFTERTRAPHOOK, NULL);
-
- traperr = errflag;
-
- /* Grab values before they are restored */
- new_trap_state = trap_state;
- new_trap_return = trap_return;
-
- execrestore();
- zcontext_restore();
-
- if (new_trap_state == TRAP_STATE_FORCE_RETURN &&
- /* zero return from function isn't special */
- !(isfunc && new_trap_return == 0)) {
- if (isfunc) {
- breaks = loops;
- /*
- * For SIGINT we behave the same as the default behaviour
- * i.e. we set the error bit indicating an interrupt.
- * We do this with SIGQUIT, too, even though we don't
- * handle SIGQUIT by default. That's to try to make
- * it behave a bit more like its normal behaviour when
- * the trap handler has told us that's what it wants.
- */
- if (sig == SIGINT || sig == SIGQUIT)
- errflag |= ERRFLAG_INT;
- else
- errflag |= ERRFLAG_ERROR;
- }
- lastval = new_trap_return;
- /* return triggered */
- retflag = 1;
- } else {
- if (traperr && !EMULATION(EMULATE_SH))
- lastval = 1;
- else {
- /*
- * With no explicit forced return, we keep the
- * lastval from before the trap ran.
- */
- lastval = olastval;
- }
- if (try_tryflag) {
- if (traperr)
- errflag |= ERRFLAG_ERROR;
- else
- errflag &= ~ERRFLAG_ERROR;
- }
- breaks += obreaks;
- /* return not triggered: restore old flag */
- retflag = oretflag;
- if (breaks > loops)
- breaks = loops;
- }
-
- /*
- * If zle was running while the trap was executed, see if we
- * need to restore the display.
- */
- if (zleactive && resetneeded)
- zleentry(ZLE_CMD_REFRESH);
-
- if (*sigtr != ZSIG_IGNORED)
- *sigtr &= ~ZSIG_IGNORED;
- intrap--;
-
- unqueue_signals();
-}
-
-/* Standard call to execute a trap for a given signal. */
-
-/**/
-void
-dotrap(int sig)
-{
- void *funcprog;
- int q = queue_signal_level();
-
- if (sigtrapped[sig] & ZSIG_FUNC) {
- HashNode hn = gettrapnode(sig, 0);
- if (hn)
- funcprog = hn;
- else {
-#ifdef DEBUG
- dputs("BUG: running function trap which has escaped.");
-#endif
- funcprog = NULL;
- }
- } else
- funcprog = siglists[sig];
-
- /*
- * Copied from dotrapargs().
- * (In fact, the gain from duplicating this appears to be virtually
- * zero. Not sure why it's here.)
- */
- if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
- return;
-
- dont_queue_signals();
-
- if (sig == SIGEXIT)
- ++in_exit_trap;
-
- dotrapargs(sig, sigtrapped+sig, funcprog);
-
- if (sig == SIGEXIT)
- --in_exit_trap;
-
- restore_queue_signals(q);
-}