符号 errno 转字符串

2024-04-15

是否有一个命令行工具可以获取符号 errno,例如EINVAL并打印相应的字符串,Invalid argument?

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

理想情况下我可以写一些类似的东西

$ 错误命令 EINVAL
无效的论点
$


AFAIK,没有一个标准工具可以完成这项工作。在某种程度上,编写一个文件并不是特别困难 - 最混乱的部分是找到要解析的正确文件(通常是,但绝不总是,/usr/include/sys/errno.h),然后采用从该数据中进行名称到数字的映射。我还没有找到使用枚举值而不是 #define 值的系统,但这可能只是时间问题。是否生成由令牌编号(EINTR 等)、令牌名称(“EINTR”等)和错误消息(“中断的系统调用”等)组成的三元组,或者是否仅使用数字也是一个有争议的问题并命名并将其留给“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
$

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

通用程序

#!/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;
}

errno.c

/*
@(#)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 的简单版本,它具有额外的功能,用于处理 syslog 和写入文件描述符文件指针。)。

stderr.h

/*
@(#)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 */

range.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 */

stdermin.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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

符号 errno 转字符串 的相关文章

  • 将 stdout 和 stderr 捕获到不同的变量中

    是否可以存储或捕获 stdout 和 stderr不同的变量 不使用临时文件 现在我这样做是为了获得标准输出out和标准错误err跑步时some command 但我会 喜欢避免临时文件 error file mktemp out some
  • Bash 将字符串转换为时间戳

    我有一个格式的字符串20141225093000这代表Dec 25 2014 09 30 00我想将原始格式转换为 unix 时间戳格式 以便我可以对其进行时间操作 我如何在 bash 中执行此操作 我可以轻松地解析出这些值expr但我希望
  • 使用 xclip 将剪贴板内容粘贴到 bash 中的变量中

    我知道这个命令会将剪贴板内容粘贴到文件中 xclip out selection clipboard gt gt file txt 如果我想将剪贴板内容粘贴到变量 如字符串 中 我该怎么办 要将命令的输出分配给变量 可以使用命令替换 myv
  • bash while 循环线程

    我有一个 while 循环读取来自 a 的行 hosts while read line do ip line check done lt hosts 我的问题是我可以使用某种方法来加快速度 或者一次在 10 个主机上运行检查 每个检查都在
  • 验证 BASH 脚本时出现问题 [已关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我在尝试验证 bash 脚本时出现代码 lint 错误 bin bash if eq 0 then printf No argum
  • 在 Unix 中,如何删除当前目录及其下面的所有内容?

    我知道这会删除子目录及其下面的所有内容 rm rf
  • bash 用变量值替换字符串中的变量名

    这有点奇怪 我有以下字符串 我有一个名为 REDIRECT 的变量设置为 https working MYDOMAIN blah blah 我需要将 MYDOMAIN 替换为分配给 MYDOMAIN 的变量的实际值 不确定 bash 还是
  • 安全地记住 bash 脚本中的 ssh 凭据[重复]

    这个问题在这里已经有答案了 假设我有一个 bash 脚本 它通过 ssh 在远程计算机上执行命令 Do something here ssh otheruser host command1 Do something else ssh oth
  • 在 bash 函数中生成后台进程

    我正在编写一个 Bash 函数来启动需要从某个文件夹启动的服务器 但我不希望启动该服务器影响我当前的工作 我写了以下内容 function startsrv pushd cd TRUNK SERVERCOMMAND popd 我的变量都已设
  • 在docker镜像中运行多个脚本

    您好 我想知道是否可以在 docker 容器启动时自动同时运行两个脚本 第一个脚本必须运行客户端应用程序 第二个脚本必须运行服务器应用程序作为后台 You can use CMD在你的Dockerfile https docs docker
  • 命令行参数中的“-”(破折号)有什么魔力?

    例子 创建 ISO 映像并将其直接刻录到 CD mkisofs V Photos r home vivek photos cdrecord v dev dev dvdrw 更改到上一个目录 cd 侦听端口 12345 并解压发送到该端口的数
  • 如何在 Bash 中将字符串转换为小写

    有办法进去吗bash questions tagged bash将字符串转换为小写字符串 例如 如果我有 a Hi all 我想将其转换为 hi all 有多种方法 POSIX标准 https en m wikipedia org wiki
  • envsubst 不能进行就地替换吗?

    我有一个配置文件 其中包含一些 ENV VARIABLE 样式的变量 This is my file It might contain EXAMPLES of text 现在我希望将该变量替换为保存在实际环境变量中的值 所以我正在尝试这个
  • Bash 中的 Shellshock 漏洞背后的行为是有记录的还是有意为之?

    最近的一个漏洞 CVE 2014 6271 http web nvd nist gov view vuln detail vulnId CVE 2014 6271 如何Bash http en wikipedia org wiki Bash
  • 参考当前命令的先前参数

    例如 我想执行以下操作 mv xxxx xxxx bak 我知道我可以使用这个命令 mv xxxx bak 我认为这在某种程度上并不直接 如果我能做到这一点那就太好了 mv xxxx 1 bak 有时我需要这样 echo xxxx yyyy
  • 如何在Windows Git shell中运行./script.sh?

    也许这很尴尬 但是当我在 Git shell 中工作时 我无法在 Windows 上运行 sh 文件 也许我必须安装一些东西 但我认为 Git 会支持 bash 命令 我知道 Windows 不使用 sh 文件 我正在执行安装步骤游戏结束
  • shell 脚本:错误的解释器:使用 pwd 时没有这样的文件或目录

    我想用 for 循环遍历目录中的文件 但这出现了 echo bad interpreter No such file or directory code bin bash count 0 dir pwd echo dir FILES ls
  • 子 shell 何时继承其父 shell 环境?

    什么情况下将shell的环境传递给子shell 子 shell 始终从父 shell 获取所有变量 man bash将描述所有使用子shell的情况 主要是 command command command and command 所谓环境只
  • 通过 SSH 将变量传递给远程脚本

    我正在通过 SSH 从本地服务器在远程服务器上运行脚本 首先使用 SCP 复制该脚本 然后在传递一些参数时调用该脚本 如下所示 scp path to script server example org another path ssh s
  • 如何从 haskell 中的 IOError 获取 errno?

    我在 haskell 平台上 GHC 6 12 1 作为 apt get 安装在 Debian Squeeze 上 鉴于我需要在与最初引发它的线程不同的线程上使用它 如何从 IOError 中获取底层 errno 我需要这个的原因是因为我正

随机推荐