如何在Linux上构建信号名称数组?

时间:2017-09-05 05:33:02

标签: c linux unix awk sed

linux上的错误号与系统有关。出于这个原因,作者 license编写了一个脚本来构建与错误号对应的名称数组。在系统上运行时,脚本将根据该系统上的错误号构建阵列。该脚本显示在下面的代码块中。

CODE ---------------------------------------------- ------------

The Linux Programming Interface

RESULT ---------------------------------------------- --------------

#!/bin/sh
#
# Create a new version of the file ename.c.inc by parsing symbolic
# error names defined in errno.h
#
echo '#include <errno.h>' | cpp -dM | 
sed -n -e '/#define  *E/s/#define  *//p' |sort -k2n |
awk '
BEGIN {
        entries_per_line = 4
        line_len = 68;
        last = 0;
        varname ="    enames";
        print "static char *ename[] = {";
        line =  "    /*   0 */ \"\"";
}

{
    if ($2 ~ /^E[A-Z0-9]*$/) {      # These entries are sorted at top
        synonym[$1] = $2;
    } else {
        while (last + 1 < $2) {
            last++;
            line = line ", ";
            if (length(line ename) > line_len || last == 1) {
                print line;
                line = "    /* " last " */ ";
                line = sprintf("    /* %3d */ ", last);
            }
            line = line "\"" "\"" ;
        }
        last = $2;
        ename = $1;
        for (k in synonym)
            if (synonym[k] == $1) ename = ename "/" k;

            line = line ", ";
            if (length(line ename) > line_len || last == 1) {
                print line;
                line = "    /* " last " */ ";
                line = sprintf("    /* %3d */ ", last);;
            }
            line = line "\"" ename "\"" ;
    }
}
END {
    print  line;
    print "};"
    print "";
    print "#define MAX_ENAME " last;
}
'

Linux上的信号编号也与系统有关,我想使用类似的脚本生成一组信号名称。我怎么能这样做?

1 个答案:

答案 0 :(得分:0)

我使用的脚本就是这个Perl脚本:

#!/usr/bin/env perl
#
# @(#)$Id: gensignal.pl,v 1.2 2013/05/31 20:56:27 jleffler Exp $
#
# Generate table of signal number constants from given file(s)

use warnings;
use strict;
use File::Temp qw( tempfile );

my %symlist;
my $maxsymlen = 0;
my $maxmsglen = 0;

die qq{Usage: $0 signal.h 'compiler and flags'\n} unless scalar(@ARGV) == 2;

my $header = $ARGV[0];
my $command = "$ARGV[1] -H -c";

my ($tfh, $name) = tempfile("gensignal-XXXXXX", SUFFIX => '.c', DIR => '.', UNLINK => 1);
print $tfh "#include <$header>\n";
close $tfh;

my @headers;
open my $nfh, "-|", "$command $name 2>&1" or die "Failed to execute command $command $name";
while (<$nfh>)
{
    chomp;
    next unless m/^\./;
    s/^\.+ //;
    push @headers, $_;
}
close $nfh;
$name =~ s/\.c$/.o/;
unlink $name;

@ARGV = @headers;

while (<>)
{
    next unless m%^\s*#\s*define\s+(SIG[A-Z0-9a-z]+)\s+(\d+)\s*/\*\s*([A-Za-z].*\S)\s*\*/%;
    $symlist{$1} = { number => $2, message => $3 };
    $maxsymlen = length($1) if length($1) > $maxsymlen;
    $maxmsglen = length($3) if length($3) > $maxmsglen;
}

my $format = sprintf "    {   %%-%ds %%-%ds %%-5s   %%-%ds },\n", $maxsymlen + 3, $maxsymlen + 1, $maxmsglen + 2;

foreach my $key (sort keys %symlist)
{
    my $name    = qq{"$key",};
    my $symbol  = qq{$key,};
    my $number  = qq{$symlist{$key}->{number},};
    my $message = qq{"$symlist{$key}->{message}"};

    print "#ifdef $key\n";
    printf $format, $name, $symbol, $number, $message;
    print "#endif\n";
}

它需要与GCC兼容的编译器 - 它使用-H选项生成头文件列表。

在Ubuntu 16.04上,输出为:

#ifdef SIGABRT
    {   "SIGABRT",   SIGABRT,   6,      "Abort (ANSI)."                         },
#endif
#ifdef SIGALRM
    {   "SIGALRM",   SIGALRM,   14,     "Alarm clock (POSIX)."                  },
#endif
#ifdef SIGBUS
    {   "SIGBUS",    SIGBUS,    7,      "BUS error (4.2 BSD)."                  },
#endif
#ifdef SIGCHLD
    {   "SIGCHLD",   SIGCHLD,   17,     "Child status has changed (POSIX)."     },
#endif
#ifdef SIGCONT
    {   "SIGCONT",   SIGCONT,   18,     "Continue (POSIX)."                     },
#endif
#ifdef SIGFPE
    {   "SIGFPE",    SIGFPE,    8,      "Floating-point exception (ANSI)."      },
#endif
#ifdef SIGHUP
    {   "SIGHUP",    SIGHUP,    1,      "Hangup (POSIX)."                       },
#endif
#ifdef SIGILL
    {   "SIGILL",    SIGILL,    4,      "Illegal instruction (ANSI)."           },
#endif
#ifdef SIGINT
    {   "SIGINT",    SIGINT,    2,      "Interrupt (ANSI)."                     },
#endif
#ifdef SIGIO
    {   "SIGIO",     SIGIO,     29,     "I/O now possible (4.2 BSD)."           },
#endif
#ifdef SIGIOT
    {   "SIGIOT",    SIGIOT,    6,      "IOT trap (4.2 BSD)."                   },
#endif
#ifdef SIGKILL
    {   "SIGKILL",   SIGKILL,   9,      "Kill, unblockable (POSIX)."            },
#endif
#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
#ifdef SIGQUIT
    {   "SIGQUIT",   SIGQUIT,   3,      "Quit (POSIX)."                         },
#endif
#ifdef SIGSEGV
    {   "SIGSEGV",   SIGSEGV,   11,     "Segmentation violation (ANSI)."        },
#endif
#ifdef SIGSTKFLT
    {   "SIGSTKFLT", SIGSTKFLT, 16,     "Stack fault."                          },
#endif
#ifdef SIGSTOP
    {   "SIGSTOP",   SIGSTOP,   19,     "Stop, unblockable (POSIX)."            },
#endif
#ifdef SIGSYS
    {   "SIGSYS",    SIGSYS,    31,     "Bad system call."                      },
#endif
#ifdef SIGTERM
    {   "SIGTERM",   SIGTERM,   15,     "Termination (ANSI)."                   },
#endif
#ifdef SIGTRAP
    {   "SIGTRAP",   SIGTRAP,   5,      "Trace trap (POSIX)."                   },
#endif
#ifdef SIGTSTP
    {   "SIGTSTP",   SIGTSTP,   20,     "Keyboard stop (POSIX)."                },
#endif
#ifdef SIGTTIN
    {   "SIGTTIN",   SIGTTIN,   21,     "Background read from tty (POSIX)."     },
#endif
#ifdef SIGTTOU
    {   "SIGTTOU",   SIGTTOU,   22,     "Background write to tty (POSIX)."      },
#endif
#ifdef SIGURG
    {   "SIGURG",    SIGURG,    23,     "Urgent condition on socket (4.2 BSD)." },
#endif
#ifdef SIGUSR1
    {   "SIGUSR1",   SIGUSR1,   10,     "User-defined signal 1 (POSIX)."        },
#endif
#ifdef SIGUSR2
    {   "SIGUSR2",   SIGUSR2,   12,     "User-defined signal 2 (POSIX)."        },
#endif
#ifdef SIGVTALRM
    {   "SIGVTALRM", SIGVTALRM, 26,     "Virtual alarm clock (4.2 BSD)."        },
#endif
#ifdef SIGWINCH
    {   "SIGWINCH",  SIGWINCH,  28,     "Window size change (4.3 BSD, Sun)."    },
#endif
#ifdef SIGXCPU
    {   "SIGXCPU",   SIGXCPU,   24,     "CPU limit exceeded (4.2 BSD)."         },
#endif
#ifdef SIGXFSZ
    {   "SIGXFSZ",   SIGXFSZ,   25,     "File size limit exceeded (4.2 BSD)."   },
#endif

您将获得标题中记录的信号名称(按排序顺序),符号,数字及其含义。

该信息应保存在gensignal.h中,然后可以编译以下代码:

/*
@(#)File:           $RCSfile: signal.c,v $
@(#)Version:        $Revision: 1.12 $
@(#)Last changed:   $Date: 2016/03/24 21:42:19 $
@(#)Purpose:        Print messages corresponding to signal number or name
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2012-13,2015-16
*/

/*TABSTOP=4*/

#define MAIN_PROGRAM
#ifndef _GNU_SOURCE
#define _GNU_SOURCE         /* Linux */
#endif
#ifndef _DARWIN_C_SOURCE
#define _DARWIN_C_SOURCE    /* Mac OS X */
#endif

/* Need O/S specific messages as well as POSIX messages */
/* Do not #include "posixver.h" */

#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "emalloc.h"
#include "jlss.h"
#include "range.h"
#include "stderr.h"

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

/*
** Generate gensignal.h using:
**     perl gensignal.pl /usr/include/sys/signal.h > gensignal.h
** NB: list must be sorted alphabetically on symbol name
*/
static const sig_info sig_msgs[] =
{
#include "gensignal.h"
};

static const sig_info sig_zero = { "SIGNONE", 0, 0, "No signal" };

static const char optstr[] = "hlqV";
static const char usestr[] = "[-hlqV] [lo[:hi] ...]";
static const char hlpstr[] =
    "  -h    Print help and exit\n"
    "  -l    Print list of all signals\n"
    "  -q    Validate signal but don't print messages\n"
    "  -V    Print version and exit\n"
    ;

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

static const sig_info *sig_nums[DIM(sig_msgs)];

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_signal_c[];
const char jlss_id_signal_c[] = "@(#)$Id: signal.c,v 1.12 2016/03/24 21:42:19 jleffler Exp $";
#endif /* lint */

static int cmp_sig_number(const void *v1, const void *v2)
{
    int e1 = (*((const sig_info * const *)v1))->signum;
    int e2 = (*((const sig_info * const *)v2))->signum;
    return(e1 - e2);
}

static void map_numbers(void)
{
    for (size_t i = 0; i < DIM(sig_msgs); i++)
        sig_nums[i] = &sig_msgs[i];
    qsort(sig_nums, DIM(sig_nums), sizeof(*sig_nums), cmp_sig_number);
}

static const sig_info *sig_info_number(int num)
{
    sig_info    lookfor = { 0, num, 0, 0 };
    sig_info   *lookptr = &lookfor;
    const sig_info **found = bsearch(&lookptr, sig_nums, DIM(sig_nums), sizeof(*sig_nums), cmp_sig_number);
    return((found != 0) ? *found : 0);
}

static int cmp_sig_symbol(const void *v1, const void *v2)
{
    const char *s1 = ((const sig_info *)v1)->sigsym;
    const char *s2 = ((const sig_info *)v2)->sigsym;
    return(strcmp(s1, s2));
}

static int pr_string_signal(const char *arg, int qflag)
{
    int estat = EXIT_SUCCESS;
    char *name = estrdup(arg);
    sig_info lookfor = { name, 0, 0, 0 };
    strupper(name);
    if (strncmp(name, "SIG", sizeof("SIG")-1) != 0)
    {
        free(name);
        name = MALLOC(strlen(arg) + sizeof("SIG"));
        strcpy(name, "SIG");
        strcpy(name + sizeof("SIG") - 1, arg);
        strupper(name);
    }
    const sig_info *found = bsearch(&lookfor, sig_msgs, DIM(sig_msgs), sizeof(*sig_msgs), cmp_sig_symbol);
    if (found == 0)
    {
        if (qflag == 0)
            err_remark("unrecognized symbol %s\n", arg);
        estat = EXIT_FAILURE;
    }
    else if (qflag == 0)
        printf("%s (%d): %s\n", found->sigsym, found->signum, found->sigmsg);
    free(name);
    return(estat);
}

static int pr_signals_range(int lo, int hi, int qflag)
{
    int estat = EXIT_SUCCESS;
    for (int msg = lo; msg <= hi; msg++)
    {
        const sig_info *info = (msg == 0) ? &sig_zero : sig_info_number(msg);
        if (info == 0)
        {
            if (qflag == 0)
                err_remark("no name for signal = %d\n", msg);
            estat = EXIT_FAILURE;
        }
        else if (qflag == 0)
            printf("%d (%s): %s\n", msg, info->sigsym, info->sigmsg);
    }
    return estat;
}

static int pr_number_signal(const char *arg, int qflag)
{
    int estat = EXIT_FAILURE;
    long lo;
    long hi;
    const char *endp;
    const char *ptr = arg;
    int max_sig = sig_nums[DIM(sig_msgs)-1]->signum;

    while ((endp = numeric_range(ptr, &lo, &hi)) != 0)
    {
        if (endp == ptr)
        {
            err_remark("Invalid range specified (%s) - should be lo[:hi]\n", ptr);
            break;
        }
        else if (lo < 0 || lo > max_sig || hi < 0 || hi > max_sig || lo > hi)
        {
            if (lo != hi)
                err_remark("Invalid signal number range %ld:%ld (valid range is 0:%d)\n",
                           lo, hi, max_sig);
            else
                err_remark("Invalid signal number %ld (valid range is 0:%d)\n",
                           hi, max_sig);
        }
        else
            estat = pr_signals_range((int)lo, (int)hi, qflag);
        ptr = endp;
    }
    return(estat);
}

static int pr_signal(char *arg, int qflag)
{
    int estat;
    if (isalpha(*arg))
        estat = pr_string_signal(arg, qflag);
    else
        estat = pr_number_signal(arg, qflag);
    return(estat);
}

static void list_signals(void)
{
    for (size_t i = 0; i < DIM(sig_msgs); i++)
    {
        char number[10];
        snprintf(number, sizeof(number), "%d", sig_nums[i]->signum);
        pr_number_signal(number, 0);
    }
}

int main(int argc, char **argv)
{
    int i;
    int opt;
    int nstat;
    int estat = EXIT_SUCCESS;
    int qflag = 0;
    int lflag = 0;

    err_setarg0(argv[0]);

    map_numbers();

    while ((opt = getopt(argc, argv, optstr)) != EOF)
    {
        switch (opt)
        {
        case 'l':
            if (qflag)
                err_error("Cannot set both -l and -q options\n");
            lflag = 1;
            break;
        case 'q':
            if (lflag)
                err_error("Cannot set both -l and -q options\n");
            qflag = 1;
            break;
        case 'V':
            err_version("SIGNAL", "$Revision: 1.12 $ ($Date: 2016/03/24 21:42:19 $)");
            /*NOTREACHED*/
        case 'h':
            err_help(usestr, hlpstr);
            /*NOTREACHED*/
        default:
            err_usage(usestr);
            /*NOTREACHED*/
        }
    }

    if (lflag)
    {
        if (optind != argc)
            err_usage(usestr);
        list_signals();
    }
    else
    {
        if (optind >= argc)
            err_usage(usestr);

        for (i = optind; i < argc; i++)
        {
            nstat = pr_signal(argv[i], qflag);
            if (nstat == EXIT_FAILURE)
                estat = nstat;
        }
    }

    return(estat);
}

您需要从https://github.com/jleffler/soq/tree/master/src/libsoq获取一堆库函数:

  • posixver.h
  • debug.h
  • emalloc.c
  • emalloc.h
  • errhelp.c
  • estrdup.c
  • jlss.h
  • kludge.h
  • range.h
  • range2.c
  • stderr.h
  • stderr.c
  • strupper.c

运行时,它会产生(例如):

$ signal hup 3 
SIGHUP (1): Hangup (POSIX).
3 (SIGQUIT): Quit (POSIX).
$