符号 errno 到字符串
Posted
技术标签:
【中文标题】符号 errno 到字符串【英文标题】:Symbolic errno to String 【发布时间】:2011-01-14 03:13:15 【问题描述】:是否有命令行工具可以接收符号错误号(例如EINVAL
)并打印相应的字符串Invalid argument
?
我想避免在我的系统上发现 EINVAL 的值为 22,然后使用$ perror 22
。
理想情况下我可以写类似的东西
$ 错误命令 EINVAL 无效参数 $
【问题讨论】:
专门 bash,但外部命令很好(/更好?) 【参考方案1】: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
$
它不处理符号错误编号的范围(读者练习)。
genrrno.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;
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 */
范围.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 */
stderrmin.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
【讨论】:
我需要对这个代码做一个小的改动,用于办公室的一个副项目;这样做可以简化。 cpp -dM -CC /usr/include/errno.h | grep 'define E' |perl generrno.pl >generrno.h 很好,只是我必须使用这个命令来生成标题。 如今,错误编号被偷偷地隐藏在不同的地方。我最终在/usr/include/errno.h
上使用gcc -H
来生成文件名列表以及错误名称和编号列表。如果您需要更新代码,请与我联系 - 请参阅我的个人资料。【参考方案2】:
至少对于 Ubuntu(12.04 及更高版本,据我所知),有一个 errno
实用程序可以通过 apt-get install errno
轻松安装。
$ errno 98
EADDRINUSE 98 Address already in use
$ errno EINVAL
EINVAL 22 Invalid argument
【讨论】:
errno
现在是 moreutils
(LP #1019999) 的一部分,它也可用于 Debian 和其他基于 Debian 的发行版。它包含在moreutils
0.47 及更高版本(Debian Wheezy、Ubuntu Trusty 及更高版本)中。
moreutils
也可以在 macOS 上使用
坦率地说,这应该是最终答案。短而甜,切中要害【参考方案3】:
这适用于 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]]
【讨论】:
【参考方案4】:功能
strerror()
可能是您正在寻找的东西,但我不知道有一个命令可以将其暴露给任何 shell。
MKS 暴露命令行strerror
【讨论】:
【参考方案5】:试过
grep EINVAL /usr/include/sys/errno.h
看到什么回来了?
【讨论】:
某些系统(例如,Linux)的头文件中包含错误代码,该代码在 #include 之后的多个级别。【参考方案6】:
#! /bin/bash -f
errorDir="/usr/include/asm-generic"
strError="$1"
numericVal=awk -v pat="$strError" '$0 ~ patprint $3' $errorDir/errno-base.h $errorDir/errno.h
perror $numericVal
注意:由于此脚本使用 ERROR MACROS 的位置,虽然它可以在我的系统上运行,但它可能无法移植。
【讨论】:
【参考方案7】:Rob Wells 部分正确。不幸的是/usr/include/asm/errno.h
是非标准的。你真的需要 grep /usr/include/errno.h
和 /usr/include/*/errno.h
。
要生成此错误命令,请尝试将其添加到您的 .bashrc 文件中:
function errorcommand
grep "$1" /usr/include/errno.h /usr/include/*/errno.h
像这样工作:
Rob Wells 部分正确。不幸的是/usr/include/asm/errno.h
是非标准的。你真的需要 grep /usr/include/errno.h
和 /usr/include/*/errno.h
。
要生成此错误命令,请尝试将其添加到您的 .bashrc 文件中:
function errorcommand
grep "$1" /usr/include/errno.h /usr/include/*/errno.h
像这样工作:
$ errorcommand EINV
/usr/include/sys/errno.h:#define EINVAL 22 /* Invalid argument */
$
【讨论】:
【参考方案8】:一个紧凑的 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】:
没有执行此操作的标准实用程序。我相信您最好的选择是自己编写这样的实用程序。使用 strerror() 打印相关的错误信息。
【讨论】:
【参考方案10】:对于想要快速在线的人:
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 */
【讨论】:
【参考方案11】:在我的公司邮箱/usr/include
不可用。所以我把这个可移植的简单解决方案(如果你有 Python)放到我的 init 文件中。如果你愿意,你可以把它折磨成一条线:
function strerror ()
python -c "import os, errno; print(os.strerror(errno.$1))"
【讨论】:
以上是关于符号 errno 到字符串的主要内容,如果未能解决你的问题,请参考以下文章
为什么IS_ERR_VALUE将负MAX_ERRNO转换为无符号长整数?
Python2.7在Windows下CMD编码为65001/utf-8时print报错[Errno 0]/[Errno 2]