Iterating over a list of possible signals

青春壹個敷衍的年華 提交于 2019-12-04 04:44:10

问题


I have some code that I want to use to print a list of signals that prints the names of the signals in the signal mask of the calling process.

The starting code that I have is below:

#include "apue.h" 
#include <errno.h> 

void 
pr_mask(const char *str) 
{ 
    sigset_t sigset; 
    int errno_save;     

    errno_save = errno; 

    if (sigprocmask(0, NULL, &sigset) < 0) { 
        err_ret("sigprocmask error"); 
    }else { 
        printf("%s", str); 
        if (sigismember(&sigset, SIGINT)) 
            printf(" SIGINT"); 
        if (sigismember(&sigset, SIGQUIT)) 
            printf(" SIGQUIT"); 
        if (sigismember(&sigset, SIGUSR1)) 
            printf(" SIGUSR1"); 
        if (sigismember(&sigset, SIGALRM)) 
            printf(" SIGALRM"); 
        printf("\n");
    } 
    errno = errno_save; 
}

The thing is, I want to do more signals than just SIGINT, SIGQUIT, SIGUSR1 and SIGALRM. I do not want to make a long list of if statements for each alarm.

I want to do something like this:

for(int i = 0; i < 32; i++) {
     printf("%s", str)
     if(sigismember(sigset, signal_array[i]))
        printf("%s", signal_array[i]);
}

Where signal_array is something like this:

signal array[32] {
    SIGINT, "SIGINT"
   ...
   ...
   ... 
}

Is there some way I can do this so it is easier for me to print out each signal? It would simplify things a lot.


回答1:


If you're looking for a list or array of signals, then I'm afraid that there isn't one defined in signal.h. The only thing you can do is define it yourself and iterate over it. If you want, you could define it in a different helper file so as not to pollute the actual code.

Example program:

#include "siglist.h"
#include <stdio.h>
#include <stddef.h>

int main(void) {
    sigset_t sigset;

    // ... initialize stuff ...

    for (size_t i = 0; i < SIGLIST_LENGTH; i++) {
        if (sigismember(&sigset, siglist[i].code))
            printf("%d - %s: %s.\n", siglist[i].code, siglist[i].name, siglist[i].description);
    }

    return 0;
}

File siglist.h (all those ifdef are needed since you cannot know beforehand which signals are defined and which aren't on the target machine):

#ifndef SIGLIST_H_INCLUDED
#define SIGLIST_H_INCLUDED

#include <signal.h>

struct siginfo {
    int code;
    char *name;
    char *description;
};

const struct siginfo siglist[] = {
#ifdef SIGABRT
    {SIGABRT  , "SIGABRT"  , "Abort signal"},
#endif
#ifdef SIGALRM
    {SIGALRM  , "SIGALRM"  , "Timer signal"},
#endif
#ifdef SIGBUS
    {SIGBUS   , "SIGBUS"   , "Bus error (bad memory access)"},
#endif
#ifdef SIGCHLD
    {SIGCHLD  , "SIGCHLD"  , "Child stopped or terminated"},
#endif
#ifdef SIGCLD
    {SIGCLD   , "SIGCLD"   , "Child stopped or terminated"},
#endif
#ifdef SIGCONT
    {SIGCONT  , "SIGCONT"  , "Continue if stopped"},
#endif
#ifdef SIGEMT
    {SIGEMT   , "SIGEMT"   , "Emulator trap"},
#endif
#ifdef SIGFPE
    {SIGFPE   , "SIGFPE"   , "Floating-point exception"},
#endif
#ifdef SIGHUP
    {SIGHUP   , "SIGHUP"   , "Hangup detected on controlling terminal or death of controlling process"},
#endif
#ifdef SIGILL
    {SIGILL   , "SIGILL"   , "Illegal Instruction"},
#endif
#ifdef SIGINFO
    {SIGINFO  , "SIGINFO"  , "Power failure"},
#endif
#ifdef SIGINT
    {SIGINT   , "SIGINT"   , "Interrupt from keyboard"},
#endif
#ifdef SIGIO
    {SIGIO    , "SIGIO"    , "I/O now possible"},
#endif
#ifdef SIGIOT
    {SIGIOT   , "SIGIOT"   , "IOT trap: Abort signal"},
#endif
#ifdef SIGKILL
    {SIGKILL  , "SIGKILL"  , "Kill signal"},
#endif
#ifdef SIGLOST
    {SIGLOST  , "SIGLOST"  , "File lock lost "},
#endif
#ifdef SIGPIPE
    {SIGPIPE  , "SIGPIPE"  , "Broken pipe: write to pipe with no readers"},
#endif
#ifdef SIGPOLL
    {SIGPOLL  , "SIGPOLL"  , "Pollable event: I/O now possible"},
#endif
#ifdef SIGPROF
    {SIGPROF  , "SIGPROF"  , "Profiling timer expired"},
#endif
#ifdef SIGPWR
    {SIGPWR   , "SIGPWR"   , "Power failure"},
#endif
#ifdef SIGQUIT
    {SIGQUIT  , "SIGQUIT"  , "Quit from keyboard"},
#endif
#ifdef SIGSEGV
    {SIGSEGV  , "SIGSEGV"  , "Invalid memory reference"},
#endif
#ifdef SIGSTKFLT
    {SIGSTKFLT, "SIGSTKFLT", "Stack fault on coprocessor"},
#endif
#ifdef SIGSTOP
    {SIGSTOP  , "SIGSTOP"  , "Stop process"},
#endif
#ifdef SIGTSTP
    {SIGTSTP  , "SIGTSTP"  , "Stop typed at terminal"},
#endif
#ifdef SIGSYS
    {SIGSYS   , "SIGSYS"   , "Bad system call "},
#endif
#ifdef SIGTERM
    {SIGTERM  , "SIGTERM"  , "Termination signal"},
#endif
#ifdef SIGTRAP
    {SIGTRAP  , "SIGTRAP"  , "Trace/breakpoint trap"},
#endif
#ifdef SIGTTIN
    {SIGTTIN  , "SIGTTIN"  , "Terminal input for background process"},
#endif
#ifdef SIGTTOU
    {SIGTTOU  , "SIGTTOU"  , "Terminal output for background process"},
#endif
#ifdef SIGUNUSED
    {SIGUNUSED, "SIGUNUSED", "Bad system call "},
#endif
#ifdef SIGURG
    {SIGURG   , "SIGURG"   , "Urgent condition on socket "},
#endif
#ifdef SIGUSR1
    {SIGUSR1  , "SIGUSR1"  , "User-defined signal 1"},
#endif
#ifdef SIGUSR2
    {SIGUSR2  , "SIGUSR2"  , "User-defined signal 2"},
#endif
#ifdef SIGVTALRM
    {SIGVTALRM, "SIGVTALRM", "Virtual alarm clock "},
#endif
#ifdef SIGXCPU
    {SIGXCPU  , "SIGXCPU"  , "CPU time limit exceeded "},
#endif
#ifdef SIGXFSZ
    {SIGXFSZ  , "SIGXFSZ"  , "File size limit exceeded"},
#endif
#ifdef SIGWINCH
    {SIGWINCH , "SIGWINCH" , "Window resize signal"},
#endif
};

const size_t SIGLIST_LENGTH = sizeof(siglist)/sizeof(siglist[0]);

#endif // SIGLIST_H_INCLUDED



回答2:


Create a structure type, and preload an array with the appropriate information:

struct SigInfo
{
    int     signum;
    char    signame[16];
};

static const struct SigInfo siginfo[] =
{
#ifdef SIGINT
        { SIGINT, "SIGINT" },
#endif
#ifdef SIGQUIT
        { SIGQUIT, "SIGQUIT" },
#endif
    …
};
enum { NUM_SIGINFO = sizeof(siginfo) / sizeof(siginfo[0]) };

And then:

printf("%s", str); 
for (int i = 0; i < NUM_SIGINFO; i++)
{
    if (sigismember(&sigset, siginfo[i].signum))
    {
        printf(" %s\n", siginfo[i].signame);
        break;
    }
}

You can package the information multiple different ways. Generating the signal information is fiddly. I use a Perl script to scrutinize the appropriate header (usually /usr/include/sys/errno.h) and extract the information shown, plus the text of what the signal is for, plus the number associated with the signal:

typedef struct sig_info
{
    const char *sigsym;     /* Signal symbol  - "EINTR" */
    int         signum;     /* Signal number  - EINTR   */
    int         sigdef;     /* Signal define  - 2       */
    const char *sigmsg;     /* Signal message - Interrupted system call */
} sig_info;

…
#ifdef SIGPIPE
    {   "SIGPIPE",   SIGPIPE,   13,   "Broken pipe (POSIX)."                  },
#endif
#ifdef SIGPROF
    {   "SIGPROF",   SIGPROF,   27,   "Profiling alarm clock (4.2 BSD)."      },
#endif
#ifdef SIGPWR
    {   "SIGPWR",    SIGPWR,    30,   "Power failure restart (System V)."     },
#endif
…

The program this comes from allows me to find signals by name or number:

$ ./signal int 2
SIGINT (2): Interrupt (ANSI).
2 (SIGINT): Interrupt (ANSI).
$ ./signal -h
Usage: signal [-hlqV] [lo[:hi] ...]
  -h    Print help and exit
  -l    Print list of all signals
  -q    Validate signal but don't print messages
  -V    Print version and exit
$ ./signal -l
1 (SIGHUP): Hangup (POSIX).
2 (SIGINT): Interrupt (ANSI).
3 (SIGQUIT): Quit (POSIX).
4 (SIGILL): Illegal instruction (ANSI).
5 (SIGTRAP): Trace trap (POSIX).
6 (SIGIOT): IOT trap (4.2 BSD).
6 (SIGIOT): IOT trap (4.2 BSD).
7 (SIGBUS): BUS error (4.2 BSD).
8 (SIGFPE): Floating-point exception (ANSI).
9 (SIGKILL): Kill, unblockable (POSIX).
10 (SIGUSR1): User-defined signal 1 (POSIX).
11 (SIGSEGV): Segmentation violation (ANSI).
12 (SIGUSR2): User-defined signal 2 (POSIX).
13 (SIGPIPE): Broken pipe (POSIX).
14 (SIGALRM): Alarm clock (POSIX).
15 (SIGTERM): Termination (ANSI).
16 (SIGSTKFLT): Stack fault.
17 (SIGCHLD): Child status has changed (POSIX).
18 (SIGCONT): Continue (POSIX).
19 (SIGSTOP): Stop, unblockable (POSIX).
20 (SIGTSTP): Keyboard stop (POSIX).
21 (SIGTTIN): Background read from tty (POSIX).
22 (SIGTTOU): Background write to tty (POSIX).
23 (SIGURG): Urgent condition on socket (4.2 BSD).
24 (SIGXCPU): CPU limit exceeded (4.2 BSD).
25 (SIGXFSZ): File size limit exceeded (4.2 BSD).
26 (SIGVTALRM): Virtual alarm clock (4.2 BSD).
27 (SIGPROF): Profiling alarm clock (4.2 BSD).
28 (SIGWINCH): Window size change (4.3 BSD, Sun).
29 (SIGIO): I/O now possible (4.2 BSD).
30 (SIGPWR): Power failure restart (System V).
31 (SIGSYS): Bad system call.
34 (SIGRT34): Real time signal 34 (SIGRTMIN)
35 (SIGRT35): Real time signal 35
…
63 (SIGRT63): Real time signal 63
64 (SIGRT64): Real time signal 64 (SIGRTMAX)
$

This particular list of signals was generated on an ancient RedHat Linux machine (5.2, IIRC). The effect is similar on macOS, and other versions of Linux too.



来源:https://stackoverflow.com/questions/57299119/iterating-over-a-list-of-possible-signals

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!