代码之家  ›  专栏  ›  技术社区  ›  Flame

符号错误到字符串

  •  10
  • Flame  · 技术社区  · 15 年前

    是否有命令行工具将采用符号errno,例如 EINVAL 打印相应的字符串, Invalid argument ?

    我想避免在我的系统中发现eival值为22,然后使用 $ perror 22 .

    理想情况下我可以写一些

    $ERRORCOMMAND电子发票
    无效参数
    $

    10 回复  |  直到 6 年前
        1
  •  6
  •   Jonathan Leffler    15 年前

    阿法克,没有一个标准的工具可以完成这项工作。在某种程度上,编写一个文件并不特别困难——最麻烦的部分是找到要分析的正确文件(通常是,但决不是总是,/usr/include/sys/errno.h),然后从中提取数据,将名称映射到数字。我没有找到使用枚举值而不是定义值的系统,但这可能只是时间问题。是否生成由令牌号(eintr等)、令牌名(eintr等)和错误消息(interrupted system call等)组成的三重信息,或者是否仅使用数字和名称并将其保留为“strError()”以提供消息,这也是一个未知数。


    如我所说,这并不特别难。我已经有了一个名为“errno”的程序,它接受纯数字值并打印相应的错误消息:

    $ errno 1:10 20
    1: Operation not permitted
    2: No such file or directory
    3: No such process
    4: Interrupted system call
    5: Input/output error
    6: Device not configured
    7: Argument list too long
    8: Exec format error
    9: Bad file descriptor
    10: No child processes
    20: Not a directory
    $
    

    我编写了一个Perl脚本并对程序进行了黑客攻击,以处理符号错误号:

    $ errno 1:4 EINTR ENOTDIR
    1 (EPERM): Operation not permitted
    2 (ENOENT): No such file or directory
    3 (ESRCH): No such process
    4 (EINTR): Interrupted system call
    EINTR (4): Interrupted system call
    ENOTDIR (20): Not a directory
    $
    

    它不处理符号错误号的范围(读者练习)。

    通用PL

    #!/usr/bin/perl -w
    #
    # @(#)$Id: generrno.pl,v 1.1 2010/02/07 18:39:18 jleffler Exp jleffler $
    #
    # Generate table of error number constants from given file(s)
    
    use strict;
    
    my %symlist;
    my $maxsymlen = 0;
    my $maxmsglen = 0;
    
    while (<>)
    {
        next unless m%^\s*#\s*define\s+(E[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}"};
    
        printf $format, $name, $symbol, $number, $message;
    }
    

    埃尔诺

    /*
    @(#)File:           $RCSfile: errno.c,v $
    @(#)Version:        $Revision: 2.2 $
    @(#)Last changed:   $Date: 2010/02/07 19:22:37 $
    @(#)Purpose:        Print messages corresponding to errno values or name
    @(#)Author:         J Leffler
    @(#)Copyright:      (C) JLSS 2003,2005,2008,2010
    */
    
    /*TABSTOP=4*/
    
    #define MAIN_PROGRAM
    
    /* Need O/S specific messages as well as POSIX messages */
    //#if __STDC_VERSION__ >= 199901L
    //#define _XOPEN_SOURCE 600
    //#else
    //#define _XOPEN_SOURCE 500
    //#endif /* __STDC_VERSION__ */
    
    #include <ctype.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h> /* getopt() on MacOS X 10.2 */
    #include "stderr.h"
    #include "range.h"
    
    typedef struct err_info
    {
        const char *errsym;     /* Error symbol - "EINTR" */
        int         errnum;     /* Error number - EINTR   */
        int         errdef;     /* Error define - 4       */
        const char *errmsg;     /* Error message - Interrupted system call */
    } err_info;
    
    /*
    ** Generate generrno.h using:
    **     perl generrno.pl /usr/include/sys/errno.h > generrno.h 
    ** NB: list must be sorted alphabetically on symbol name
    */
    static const err_info err_msgs[] =
    {
    #include "generrno.h"
    };
    
    static const char usestr[] = "[-qV] [--] lo[:hi] ...";
    
    #define DIM(x)  (sizeof(x)/sizeof(*(x)))
    
    static const err_info *err_nums[DIM(err_msgs)];
    
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_errno_c[] = "@(#)$Id: errno.c,v 2.2 2010/02/07 19:22:37 jleffler Exp $";
    #endif /* lint */
    
    static int cmp_err_number(const void *v1, const void *v2)
    {
        int e1 = (*((const err_info * const *)v1))->errnum;
        int e2 = (*((const err_info * const *)v2))->errnum;
        return(e1 - e2);
    }
    
    static void map_numbers(void)
    {
        int i;
    
        for (i = 0; i < DIM(err_msgs); i++)
            err_nums[i] = &err_msgs[i];
        qsort(err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
    }
    
    static const char *err_symbol(int num)
    {
        const char *sym = "<UNKNOWN>";
        err_info    lookfor = { 0, num, 0, 0 };
        err_info   *lookptr = &lookfor;
        const err_info **found = bsearch(&lookptr, err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
        if (found != 0)
            sym = (*found)->errsym;
        return(sym);
    }
    
    static int cmp_err_symbol(const void *v1, const void *v2)
    {
        const char *s1 = ((const err_info *)v1)->errsym;
        const char *s2 = ((const err_info *)v2)->errsym;
        return(strcmp(s1, s2));
    }
    
    static int pr_string_errno(const char *arg, int qflag)
    {
        int estat = EXIT_SUCCESS;
        err_info lookfor = { arg, 0, 0, 0 };
        const err_info *found = bsearch(&lookfor, err_msgs, DIM(err_msgs), sizeof(*err_msgs), cmp_err_symbol);
        if (found == 0)
        {
            err_remark("unrecognized symbol %s\n", arg);
            estat = EXIT_FAILURE;
        }
        else if (qflag == 0)
            printf("%s (%d): %s\n", arg, found->errnum, found->errmsg);
        return(estat);
    }
    
    static int pr_number_errno(const char *arg, int qflag)
    {
        int estat = EXIT_SUCCESS;
        long lo;
        long hi;
        const char *endp;
        long msg;
    
        endp = numeric_range(arg, &lo, &hi);
        if (endp == arg)
            err_remark("Invalid range specified (%s) - should be lo[:hi]\n", arg);
        else if (*endp != '\0')
            err_remark("Non-numeric character (%c) after range '%s'\n",
                        (isprint((unsigned char)*endp) ? *endp : '?'), arg);
        else
        {
            for (msg = lo; msg <= hi; msg++)
            {
                char *msgtxt = strerror(msg);
                if (msgtxt == 0)
                {
                    err_remark("no message for errno = %ld\n", msg);
                    estat = EXIT_FAILURE;
                }
                else if (qflag == 0)
                    printf("%ld (%s): %s\n", msg, err_symbol(msg), msgtxt);
            }
        }
        return(estat);
    }
    
    static int pr_errno(char *arg, int qflag)
    {
        int estat;
        if (isalpha(*arg))
            estat = pr_string_errno(arg, qflag);
        else
            estat = pr_number_errno(arg, qflag);
        return(estat);
    }
    
    int main(int argc, char **argv)
    {
        int i;
        int opt;
        int nstat;
        int estat = EXIT_SUCCESS;
        int qflag = 0;
        int nflag = 0;
    
        err_setarg0(argv[0]);
    
        map_numbers();
    
        while ((opt = getopt(argc, argv, "qV0:1:2:3:4:5:6:7:8:9:")) != EOF)
        {
            switch (opt)
            {
            case 'q':
                qflag = 1;
                break;
            case 'V':
                err_version("ERRNO", "$Revision: 2.2 $ ($Date: 2010/02/07 19:22:37 $)");
                break;
    
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                /* GETOPT() is probably not the right tool for this job! */
                nstat = pr_errno(optarg-2, qflag);
                if (estat == EXIT_SUCCESS)
                    estat = nstat;
                nflag = 1;
                break;
    
            default:
                err_usage(usestr);
                break;
            }
        }
    
        if (optind >= argc && nflag == 0)
            err_usage(usestr);
    
        for (i = optind; i < argc; i++)
        {
            nstat = pr_errno(argv[i], qflag);
            if (estat == EXIT_SUCCESS)
                estat = nstat;
        }
    
        return(estat);
    }
    

    代码需要一些支持文件——stderr.h、range.h、range2.c和stderrmin.c(我通常使用的stderr.c的一个简单版本,它有额外的铃声和口哨,用于处理系统日志和写入文件描述符,而不是文件指针)。

    史迪尔

    /*
    @(#)File:           $RCSfile: stderr.h,v $
    @(#)Version:        $Revision: 9.2 $
    @(#)Last changed:   $Date: 2009/03/06 06:52:26 $
    @(#)Purpose:        Header file for standard error functions
    @(#)Author:         J Leffler
    @(#)Copyright:      (C) JLSS 1989-93,1996-99,2003,2005-09
    @(#)Product:        :PRODUCT:
    */
    
    #ifndef STDERR_H
    #define STDERR_H
    
    #ifdef MAIN_PROGRAM
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_stderr_h[] = "@(#)$Id: stderr.h,v 9.2 2009/03/06 06:52:26 jleffler Exp $";
    #endif /* lint */
    #endif
    
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif /* HAVE_CONFIG_H */
    
    #include <stdio.h>
    #include <stdarg.h>
    
    #ifdef __GNUC__
    #define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
    #define NORETURN()      __attribute__((noreturn))
    #else
    #define PRINTFLIKE(n,m) /* If only */
    #define NORETURN()      /* If only */
    #endif /* __GNUC__ */
    
    /* -- Definitions for error handling */
    
    enum { ERR_STAT    = 1 };           /* Default exit status     */
    
    enum { ERR_DEFAULT = 0x0000 };      /* Default flag             */
    enum { ERR_NOFLUSH = 0x0001 };      /* Do not flush open files  */
    enum { ERR_EXIT    = 0x0004 };      /* Exit  -- do not return   */
    enum { ERR_ABORT   = 0x0008 };      /* Abort -- do not return   */
    enum { ERR_STAMP   = 0x0020 };      /* Timestamp messages       */
    enum { ERR_NOARG0  = 0x0040 };      /* Do not print arg0 prefix */
    enum { ERR_PID     = 0x0080 };      /* Include pid=nnnnn info   */
    enum { ERR_ERRNO   = 0x0100 };      /* Include system error     */
    
    #ifdef USE_STDERR_SYSLOG
    /* Definitions related to using syslog */
    enum { ERR_LOG_EMERG    = 0x01000 };    /* system is unusable */
    enum { ERR_LOG_ALERT    = 0x02000 };    /* action must be taken immediately */
    enum { ERR_LOG_CRIT     = 0x04000 };    /* critical conditions */
    enum { ERR_LOG_ERR      = 0x08000 };    /* error conditions */
    enum { ERR_LOG_WARNING  = 0x10000 };    /* warning conditions */
    enum { ERR_LOG_NOTICE   = 0x20000 };    /* normal but signification condition */
    enum { ERR_LOG_INFO     = 0x40000 };    /* informational */
    enum { ERR_LOG_DEBUG    = 0x80000 };    /* debug-level messages */
    enum { ERR_LOG_LEVEL_HI = ERR_LOG_EMERG|ERR_LOG_ALERT|ERR_LOG_CRIT|ERR_LOG_ERR };
    enum { ERR_LOG_LEVEL_LO = ERR_LOG_WARNING|ERR_LOG_NOTICE|ERR_LOG_INFO|ERR_LOG_DEBUG };
    enum { ERR_LOG_LEVEL    = ERR_LOG_LEVEL_HI|ERR_LOG_LEVEL_LO };
    #endif /* USE_STDERR_SYSLOG */
    
    /* -- Standard combinations of flags */
    
    enum { ERR_REM    = ERR_DEFAULT       };
    enum { ERR_ERR    = ERR_EXIT          };
    enum { ERR_ABT    = ERR_ABORT         };
    enum { ERR_LOG    = ERR_STAMP|ERR_PID };
    enum { ERR_SYSREM = ERR_REM|ERR_ERRNO };
    enum { ERR_SYSERR = ERR_ERR|ERR_ERRNO };
    
    /* -- Maximum recorded length of argv[0]; extra is truncated */
    
    enum { ERR_MAXLEN_ARGV0 = 63 };
    
    /* -- Global definitions */
    
    extern const char  err_format1[];    /* "%s\n"    - for one string argument */
    extern const char  err_format2[];    /* "%s %s\n" - for two string arguments */
    
    extern const char *err_getarg0(void);
    extern void        err_setarg0(const char *argv0);
    
    extern FILE       *err_stderr(FILE *fp);
    extern const char *err_rcs_string(const char *s, char *buffer, size_t buflen);
    
    extern void err_abort(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
    extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
    extern void err_error1(const char *s1) NORETURN();
    extern void err_error2(const char *s1, const char *s2) NORETURN();
    extern void err_help(const char *use_str, const char *hlp_str) NORETURN();
    extern void err_helplist(const char *use_str, const char * const *help_list) NORETURN();
    extern void err_internal(const char *function, const char *msg) NORETURN();
    extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5);
    extern void err_print(int flags, int estat, const char *format, va_list args);
    extern void err_printversion(const char *program, const char *verinfo);
    extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
    extern void err_remark1(const char *s1);
    extern void err_remark2(const char *s1, const char *s2);
    extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4);
    extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
    extern void err_syserr1(const char *s1) NORETURN();
    extern void err_syserr2(const char *s1, const char *s2) NORETURN();
    extern void err_sysrem(const char *format, ...) PRINTFLIKE(1,2);
    extern void err_sysrem1(const char *s1);
    extern void err_sysrem2(const char *s1, const char *s2);
    extern void err_usage(const char *usestr) NORETURN();
    extern void err_version(const char *program, const char *verinfo) NORETURN();
    
    extern int  err_getlogopts(void);           /* Get default log options */
    extern int  err_setlogopts(int new_opts);   /* Set default log options */
    
    #ifdef USE_STDERR_FILEDESC
    extern int  err_use_fd(int fd);             /* Use file descriptor */
    #endif /* USE_STDERR_FILEDESC */
    #ifdef USE_STDERR_SYSLOG
    /* In case of doubt, use zero for both logopts and facility */
    extern int  err_use_syslog(int logopts, int facility);  /* Configure/use syslog() */
    #endif /* USE_STDERR_SYSLOG */
    
    /*
    ** JL 2003-07-31: Security Note.
    ** Question: given that err_remark("abc\n") and err_remark1("abc")
    **           produce the same output, when should you use err_remark1()
    **           instead of err_remark()?
    ** Answer 1: trivia - when you can't put the newline in the string.
    ** Answer 2: security - when the argument contains user input and could,
    **           therefore, contain conversion specifiers, etc.  The code in
    **           err_remark() does not (and cannot) verify that you have
    **           passed correct arguments for the conversion specifiers in
    **           the format string.
    ** Answer 3: inertia - when migrating code that uses remark().
    **
    ** Generalizing: when you use a function that has 'const char *format'
    ** in the prototype above, make sure your code is fully in charge of the
    ** format string to avoid security lapses.  Do not allow the user to
    ** provide that string unless you stringently check it beforehand.
    */
    
    #endif /* STDERR_H */
    

    范围h

    /*
    @(#)File:           $RCSfile: range.h,v $
    @(#)Version:        $Revision: 1.8 $
    @(#)Last changed:   $Date: 2008/02/11 07:39:36 $
    @(#)Purpose:        Declaration of range parsing functions
    @(#)Author:         J Leffler
    @(#)Copyright:      (C) JLSS 1997,2005,2007-08
    @(#)Product:        :PRODUCT:
    */
    
    /*TABSTOP=4*/
    
    #ifndef RANGE_H
    #define RANGE_H
    
    #ifdef MAIN_PROGRAM
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_range_h[] = "@(#)$Id: range.h,v 1.8 2008/02/11 07:39:36 jleffler Exp $";
    #endif /* lint */
    #endif /* MAIN_PROGRAM */
    
    /*
    ** parse_range(): parse range of non-negative numbers.
    **
    ** Given a string, parse_range() returns the lo and hi values corresponding
    ** to the range specified by the string.  For example:
    **      Input:          Low             High
    **      23              23              23
    **      23-25           23              25
    **      23-             23              0
    **      -23             0               23
    ** Any delimiter other than '-' before or after a number terminates the
    ** scan, but commas are skipped.  Returns pointer to character after
    ** last character parsed (which may or may not be '\0') if successful.
    ** Otherwise, returns null.
    **
    ** Idiomatic use:
    **
    **  const char *ptr = source_string;
    **  const char *nxt;
    **  while ((nxt = parse_range(ptr, &lo, &hi)) != 0)
    **  {
    **      if (nxt == ptr)
    **          err_error("invalid range string (%s)\n", source_string);
    **      use_range(lo, hi);
    **      ptr = nxt;
    **  }
    */
    extern const char *parse_range(const char *str, long *lo, long *hi);
    
    /*
    ** numeric_range(): parse range of numbers, positive or negative.
    **
    **  Input:      Low     High
    **  23          23      23
    **  -23        -23     -23
    **  23:25       23      25
    **  23..25      23      25
    **  -23..-25   -25     -23
    **  -23..25    -23      25
    **  23..-25    -25      23
    **  Returns pointer to '\0' at end of string if OK, sets *lo and *hi,
    **  and guarantees *lo <= *hi.
    **  Otherwise, returns pointer to start of string and does not set *lo or *hi.
    **
    ** Idiomatic use:
    **
    **  const char *ptr = source_string;
    **  const char *nxt;
    **  while ((nxt = numeric_range(ptr, &lo, &hi)) != 0)
    **  {
    **      if (nxt == ptr)
    **          err_error("invalid range string (%s)\n", source_string);
    **      use_range(lo, hi);
    **      ptr = nxt;
    **  }
    */
    extern const char *numeric_range(const char *str, long *lo, long *hi);
    
    #endif /* RANGE_H */
    

    Range2.c

    /*
    @(#)File:           $RCSfile: range2.c,v $
    @(#)Version:        $Revision: 1.8 $
    @(#)Last changed:   $Date: 2008/02/11 08:44:50 $
    @(#)Purpose:        Decode string into range of integers.
    @(#)Author:         J Leffler
    @(#)Copyright:      (C) JLSS 1997,2002,2005,2007-08
    @(#)Product:        :PRODUCT:
    */
    
    /*TABSTOP=4*/
    
    /*
    **  Parse number ranges, dealing with positive and negative values,
    **  and ranges separated by either colon or double-dot.
    **
    **  Input:      Low     High
    **  23          23      23
    **  -23        -23     -23
    **  23:25       23      25
    **  23..25      23      25
    **  -23..-25   -25     -23
    **  -23..25    -23      25
    **  23..-25    -25      23
    **  -23..+25   -23      25
    **  Any other delimiter after number (or before number) terminates
    **  input.  NB: a leading colon (or dot) is not a valid range.  If
    **  there is a format error, the returned pointer points to the
    **  start of the string (and lo and hi are unchanged).  If there is
    **  no error, then the returned pointer points to the ASCII NUL at
    **  the end of the string.
    */
    
    #include "range.h"
    #include <stdlib.h>
    
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_range2_c[] = "@(#)$Id: range2.c,v 1.8 2008/02/11 08:44:50 jleffler Exp $";
    #endif /* lint */
    
    /*
    ** Parse numeric range.
    ** Return pointer to trailing '\0' if OK, else pointer to input string
    */
    const char *numeric_range(const char *str, long *lo, long *hi)
    {
        const char *s = str;
        char       *t;
        long        l;
        long        h;
    
        l = strtol(s, &t, 10);
        if (*t == '\0')
        {
            /* Just one number */
            *lo = *hi = l;
            return(t);
        }
    
        if (*t == ':')
            t += 1;
        else if (t[0] == '.' && t[1] == '.')
            t += 2;
        else
        {
            /* Format error */
            return(str);
        }
    
        h = strtol(t, &t, 10);
        if (*t != '\0')
        {
            /* Format error */
            return(str);
        }
    
        if (h < l)
        {
            long x = h;
            h = l;
            l = x;
        }
    
        *lo = l;
        *hi = h;
    
        return(t);
    }
    
    #ifdef TEST
    #include <stdio.h>
    #include "stderr.h"
    
    int main(int argc, char **argv)
    {
        int         i;
        long        lo;
        long        hi;
        const char *t;
        const char *s;
    
        err_setarg0(argv[0]);
        if (argc <= 1)
            err_usage("range [...]");
        for (i = 1; i < argc; i++)
        {
            t = argv[i];
            if (t != 0 && *t != '\0')
            {
                printf("Parse: %15s (addr = 0x%08lX) ", t, (unsigned long)t);
                fflush(stdout);
                s = numeric_range(t, &lo, &hi);
                printf("Range: %2ld -> %2ld (addr = 0x%08lX; trailer = <<%s>>)\n", lo, hi, (unsigned long)s, s);
                fflush(stdout);
            }
        }
        return(0);
    }
    #endif /* TEST */
    

    克氏菌素C

    这是大约400行,而不是大约700行。是的,对这个程序来说太过分了;我不只是在这个程序中使用它。

    /*
    @(#)File:           $RCSfile: stderrmin.c,v $
    @(#)Version:        $Revision: 9.6 $
    @(#)Last changed:   $Date: 2009/03/02 20:27:38 $
    @(#)Purpose:        Minimal implementation of error reporting routines
    @(#)Author:         J Leffler
    @(#)Copyright:      (C) JLSS 1988-91,1996-99,2001,2003,2005-09
    @(#)Product:        :PRODUCT:
    */
    
    /*TABSTOP=4*/
    
    #undef STDERR_EXTENDED
    #include "stderr.h"
    
    #include <assert.h>
    #include <ctype.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <time.h>
    
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #else
    extern int getpid(void);
    #endif /* HAVE_UNISTD_H */
    
    enum { MAX_MSGLEN = 2048 };
    
    /* Global format strings */
    const char err_format1[] = "%s\n";
    const char err_format2[] = "%s %s\n";
    
    static const char  def_format[] = "%Y-%m-%d %H:%M:%S";
    static const char *tm_format = def_format;
    static char        arg0[ERR_MAXLEN_ARGV0+1] = "**undefined**";
    
    /* Permitted default error flags */
    enum { ERR_LOGOPTS = ERR_NOFLUSH | ERR_EXIT | ERR_ABORT | ERR_STAMP |
                         ERR_NOARG0  | ERR_PID  | ERR_ERRNO };
    static int   err_flags = 0;     /* Default error flags (ERR_STAMP, ERR_PID, etc) */
    static FILE *errout    = 0;
    
    /*
    ** err_???_print() functions are named systematically, and are all static.
    **
    ** err_[ev][crx][fn]_print():
    ** --   e   takes ellipsis argument
    ** --   v   takes va_list argument
    ** --   c   conditionally exits
    ** --   r   returns (no exit)
    ** --   x   exits (no return)
    ** --   f   takes file pointer
    ** --   n   no file pointer (use errout)
    **
    ** NB: no-return and printf-like can only be attached to declarations, not definitions.
    */
    
    static void err_vxf_print(FILE *fp, int flags, int estat, const char *format, va_list args)
                    NORETURN();
    static void err_vxn_print(int flags, int estat, const char *format, va_list args)
                    NORETURN();
    static void err_exn_print(int flags, int estat, const char *format, ...)
                    NORETURN() PRINTFLIKE(3,4);
    static void err_terminate(int flags, int estat) NORETURN();
    
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_stderrmin_c[] = "@(#)$Id: stderrmin.c,v 9.6 2009/03/02 20:27:38 jleffler Exp $";
    #endif /* lint */
    
    /*
    ** Set default log options, returning old value.
    ** Setting ERR_EXIT and ERR_ABORT is permitted but not recommended.
    */
    int err_setlogopts(int new_opts)
    {
        int old_opts = err_flags;
        err_flags = new_opts & ERR_LOGOPTS;
        return(old_opts);
    }
    
    /* Return default log options */
    int err_getlogopts(void)
    {
        return(err_flags);
    }
    
    /* Change the definition of 'stderr', reporting on the old one too */
    /* NB: using err_stderr((FILE *)0) simply reports the current 'stderr' */
    FILE *(err_stderr)(FILE *newerr)
    {
        FILE *old;
    
        if (errout == 0)
            errout = stderr;
        old = errout;
        if (newerr != 0)
            errout = newerr;
        return(old);
    }
    
    /* Return stored basename of command */
    const char *(err_getarg0)(void)
    {
        return(arg0);
    }
    
    /* Store basename of command, excluding trailing slashes */
    void (err_setarg0)(const char *argv0)
    {
        /* Ignore three pathological program names -- NULL, "/" and "" */
        if (argv0 != 0 && *argv0 != '\0' && (*argv0 != '/' || *(argv0 + 1) != '\0'))
        {
            const char *cp;
            size_t nbytes = sizeof(arg0) - 1;
    
            if ((cp = strrchr(argv0, '/')) == 0)
            {
                /* Basename of file only */
                cp = argv0;
            }
            else if (*(cp + 1) != '\0')
            {
                /* Regular pathname containing slashes but not trailing slashes */
                cp++;
            }
            else
            {
                /* Skip backwards over trailing slashes */
                const char *ep = cp;
                while (ep > argv0 && *ep == '/')
                    ep--;
                /* Skip backwards over non-slashes */
                cp = ep;
                while (cp > argv0 && *cp != '/')
                    cp--;
                assert(ep >= cp);
                cp++;
                nbytes = (size_t)(ep - cp) + 1;
                if (nbytes > sizeof(arg0) - 1)
                    nbytes = sizeof(arg0) - 1;
            }
            strncpy(arg0, cp, nbytes);
            arg0[nbytes] = '\0';
        }
    }
    
    const char *(err_rcs_string)(const char *s2, char *buffer, size_t buflen)
    {
        const char *src = s2;
        char *dst = buffer;
        char *end = buffer + buflen - 1;
    
        /*
        ** Bother RCS!  We've probably been given something like:
        ** "$Revision: 9.6 $ ($Date: 2009/03/02 20:27:38 $)"
        ** We only want to emit "7.5 (2001/08/11 06:25:48)".
        ** Skip the components between '$' and ': ', copy up to ' $',
        ** repeating as necessary.  And we have to test for overflow!
        ** Also work with the unexpanded forms of keywords ($Keyword$).
        ** Never needed this with SCCS!
        */
        while (*src != '\0' && dst < end)
        {
            while (*src != '\0' && *src != '$')
            {
                *dst++ = *src++;
                if (dst >= end)
                    break;
            }
            if (*src == '$')
                src++;
            while (*src != '\0' && *src != ':' && *src != '$')
                src++;
            if (*src == '\0')
                break;
            if (*src == '$')
            {
                /* Unexpanded keyword '$Keyword$' notation */
                src++;
                continue;
            }
            if (*src == ':')
                src++;
            if (*src == ' ')
                src++;
            while (*src != '\0' && *src != '$')
            {
                /* Map / in 2009/02/15 to dash */
                /* Heuristic - maps slashes surrounded by digits to dashes */
                char c = *src++;
                if (c == '/' && isdigit(*src) && isdigit(*(src-2)))
                    c = '-';
                *dst++ = c;
                if (dst >= end)
                    break;
            }
            if (*src == '$')
            {
                if (*(dst-1) == ' ')
                    dst--;
                src++;
            }
        }
        *dst = '\0';
        return(buffer);
    }
    
    /* Format a time string for now (using ISO8601 format) */
    /* Allow for future settable time format with tm_format */
    static char *err_time(char *buffer, size_t buflen)
    {
        time_t  now;
        struct tm *tp;
    
        now = time((time_t *)0);
        tp = localtime(&now);
        strftime(buffer, buflen, tm_format, tp);
        return(buffer);
    }
    
    /* Most fundamental (and flexible) error message printing routine - always returns */
    static
    
        2
  •  3
  •   jdzions    8 年前

    至少对于Ubuntu(12.04及更高版本,据我所知),有一个 errno 实用工具,您可以通过 apt-get install errno .

    $ errno 98
    EADDRINUSE 98 Address already in use
    $ errno EINVAL
    EINVAL 22 Invalid argument
    
        3
  •  2
  •   John Weldon user3678248    15 年前

    函数

    strerror()
    

    可能是你要找的,但我不知道有一个命令能把它暴露在任何空壳里。

    MKS 显示命令行 strerror

        4
  •  2
  •   Joao da Silva    15 年前

    这适用于Ubuntu 9.04:

    user@host:~$ grep EINVAL /usr/include/asm-generic/errno*.h
    /usr/include/asm-generic/errno-base.h:#define   EINVAL      22  /* Invalid argument */
    

    您还可以尝试使用python脚本:

    import errno
    from os import strerror
    from sys import argv
    print strerror(errno.__dict__[argv[1]]
    
        5
  •  1
  •   Rob Wells    15 年前

    尝试

    grep EINVAL /usr/include/sys/errno.h
    

    看到什么了吗?

        6
  •  1
  •   sud03r    15 年前

    
    #! /bin/bash -f
    
    

    errorDir="/usr/include/asm-generic" strError="$1" numericVal=awk -v pat="$strError" '$0 ~ pat{print $3}' $errorDir/errno-base.h $errorDir/errno.h perror $numericVal

    警告:由于此脚本使用错误宏的位置,因此虽然它在我的系统上工作,但它可能不可移植。

        7
  •  1
  •   vy32    15 年前

    罗伯·威尔斯是部分正确的。不幸的是 /usr/include/asm/errno.h 是非标准的。你真的需要变好 /usr/include/errno.h /usr/include/*/errno.h .

    要生成此错误命令,请尝试将其添加到.bashrc文件中:

    function errorcommand
    {
        grep "${1}"  /usr/include/errno.h /usr/include/*/errno.h
    }
    

    工作原理如下:

    罗伯·威尔斯是部分正确的。不幸地 /usr/include/asm/errno.h 是非标准的。你真的需要变好 /USR/包含/错误号H /usr/包含/*/错误号h .

    要生成此错误命令,请尝试将其添加到.bashrc文件中:

    功能错误命令
    {
    grep“$1”/usr/include/errno.h/usr/include/*/errno.h
    }
    

    工作原理如下:

    $ errorcommand EINV
    /usr/include/sys/errno.h:#define    EINVAL      22      /* Invalid argument */
    $
    
        8
  •  1
  •   sud03r    15 年前

    一个紧凑的bash脚本,可以完全满足您的需要:

    
    #!/bin/bash -f
    
    file="/tmp/prog$$.c"
    out="/tmp/prog$$"
    
    if [ $# -ne 1 ]
    then
        echo "Usage: $0 ERROR-NO"
        exit 1
    fi
    
    echo "#include <stdio.h>" >> $file
    echo "#include <errno.h>" >> $file
    echo "int main(){" >> $file
    echo "printf(\"$1:%s\n\",strerror($1));" >> $file
    echo "}" >> $file
    gcc $file -o $out &> /dev/null
    
    if [ $? == "0" ]
    then
        $out
        rm -f $out
    else
        echo "Syntax Error: $1 Unknown"
    fi
    
    # cleanup the file
    rm -f $file
    
    
        9
  •  0
  •   Steve Emmerson    15 年前

    这样做没有标准的实用程序。我相信你最好的办法就是自己写这样一个实用程序。使用strerror()打印关联的错误消息。

        10
  •  0
  •   Jem Tucker    6 年前

    对于想要快速、在线的人:

    find /usr/include/ -name errno*.h -exec grep ERRNO {} +
    

    例如

    [x@localhost]$ find /usr/include/ -name errno*.h -exec grep EINVAL {} +
    /usr/include/asm-generic/errno-base.h:#define   EINVAL          22      /* Invalid argument */
    
    [x@localhost]$ find /usr/include/ -name errno*.h -exec grep 111 {} +
    /usr/include/asm-generic/errno.h:#define        ECONNREFUSED    111     /* Connection refused */