how to specify nftw flags - flags

This is my nftw function, it works correctly before specifying flags FTW_DEPTH and FTW_PHYS:
if (nftw(argv[1], visit, 64, FTW_DEPTH | FTW_PHYS) != 0)
{
perror("nftw");
}
Also I have defined visit as:
int visit(const char *path, const struct stat *stat, int flags)
{
...
return 0;
}
BUT after compilation it gives error:
‘FTW_DEPTH’ undeclared (first use in this function)

Try using #define _XOPEN_SOURCE 500 before including ftw.h

if you look at ftw.h you see these lines :
#ifdef __USE_XOPEN_EXTENDED
/* Flags for fourth argument of `nftw'. */
enum
{
FTW_PHYS = 1, /* Perform physical walk, ignore symlinks. */
# define FTW_PHYS FTW_PHYS
FTW_MOUNT = 2, /* Report only files on same file system as the
argument. */
# define FTW_MOUNT FTW_MOUNT
FTW_CHDIR = 4, /* Change to current directory while processing it. */
# define FTW_CHDIR FTW_CHDIR
FTW_DEPTH = 8 /* Report files in directory before directory itself.*/
# define FTW_DEPTH FTW_DEPTH
# ifdef __USE_GNU
,
FTW_ACTIONRETVAL = 16 /* Assume callback to return FTW_* values instead of
zero to continue and non-zero to terminate. */
# define FTW_ACTIONRETVAL FTW_ACTIONRETVAL
# endif
};
so you can define this flag and error would be resolved:
#define __USE_XOPEN_EXTENDED

Related

mq_send: glibc forces param 2 to be nonnull

My static code analysis has found a bug in my code. I try to send an empty message:
mq_send(mqId, 0, 0, 1);
It says, the message buffer (parameter 2) should not be 0. It says this because the header says so:
glibc-2.29/rt/mqueue.h
/* Add message pointed by MSG_PTR to message queue MQDES. */
extern int mq_send (mqd_t __mqdes, const char *__msg_ptr, size_t __msg_len,
unsigned int __msg_prio) __nonnull ((2));
glibc-2.29/sys/cdefs.h
/* The nonull function attribute allows to mark pointer parameters which
must not be NULL. */
#if __GNUC_PREREQ (3,3)
# define __nonnull(params) __attribute__ ((__nonnull__ params))
#else
# define __nonnull(params)
#endif
I know how to fix this. I just wonder: is this correctly implemented in glibc?
Neither linux man nor the posix standard says anything about passing a nullpointer. No error code or undefined behavior is described. In fact, when the length is 0, a null pointer is totally valid and works!

How to dump/list all kernel symbols with addresses from Linux kernel module?

In a kernel module, how to list all the kernel symbols with their addresses?
The kernel should not be re-compiled.
I know "cat /proc/kallsyms" in an interface, but how to get them directly from kernel data structures, using functions like kallsyms_lookup_name.
Example
Working module code:
#include <linux/module.h>
#include <linux/kallsyms.h>
static int prsyms_print_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
pr_info("### %lx\t%s\n", address, namebuf);
return 0;
}
static int __init prsyms_init(void)
{
kallsyms_on_each_symbol(prsyms_print_symbol, NULL);
return 0;
}
static void __exit prsyms_exit(void)
{
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
Explanation
kernel/kallsyms.c implements /proc/kallsyms. Some of its functions are available for external usage. They are exported via EXPORT_SYMBOL_GPL() macro. Yes, your module should have GPL license to use it. Those functions are:
kallsyms_lookup_name()
kallsyms_on_each_symbol()
sprint_symbol()
sprint_symbol_no_offset()
To use those functions, include <linux/kallsyms.h> in your module. It should be mentioned that CONFIG_KALLSYMS must be enabled (=y) in your kernel configuration.
To print all the symbols you obviously have to use kallsyms_on_each_symbol() function. The documentation says next about it:
/* Call a function on each kallsyms symbol in the core kernel */
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long), void *data);
where fn is your callback function that should be called for each symbol found, and data is a pointer to some private data of yours (will be passed as first parameter to your callback function).
Callback function must have next signature:
int fn(void *data, const char *namebuf, struct module *module,
unsigned long address);
This function will be called for each kernel symbol with next parameters:
data: will contain pointer to your private data you passed as last argument to kallsyms_on_each_symbol()
namebuf: will contain name of current kernel symbol
module: will always be NULL, just ignore that
address: will contain address of current kernel symbol
Return value should always be 0 (on non-zero return value the iteration through symbols will be interrupted).
Supplemental
Answering the questions in your comment.
Also, is there a way to output the size of each function?
Yes, you can use sprint_symbol() function I mentioned above to do that. It will print symbol information in next format:
symbol_name+offset/size [module_name]
Example:
psmouse_poll+0x0/0x30 [psmouse]
Module name part can be omitted if symbol is built-in.
I tried the module and see the result with "dmesg". But a lot of symbols are missing such as "futex_requeue". The output symbol number is about 10K, while it is 100K when I use "nm vmlinux".
This is most likely because your printk buffer size is insufficient to store all the output of module above.
Let's improve above module a bit, so it provides symbols information via miscdevice. Also let's add function size to the output, as requested. The code as follows:
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/sizes.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#define DEVICE_NAME "prsyms2"
/* 16 MiB is sufficient to store information about approx. 200K symbols */
#define SYMBOLS_BUF_SIZE SZ_16M
struct symbols {
char *buf;
size_t pos;
};
static struct symbols symbols;
/* ---- misc char device definitions ---- */
static ssize_t prsyms2_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
return simple_read_from_buffer(buf, count, pos, symbols.buf,
symbols.pos);
}
static const struct file_operations prsyms2_fops = {
.owner = THIS_MODULE,
.read = prsyms2_read,
};
static struct miscdevice prsyms2_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &prsyms2_fops,
};
/* ---- module init/exit definitions ---- */
static int prsyms2_store_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
struct symbols *s = data;
int count;
/* Append address of current symbol */
count = sprintf(s->buf + s->pos, "%lx\t", address);
s->pos += count;
/* Append name, offset, size and module name of current symbol */
count = sprint_symbol(s->buf + s->pos, address);
s->pos += count;
s->buf[s->pos++] = '\n';
if (s->pos >= SYMBOLS_BUF_SIZE)
return -ENOMEM;
return 0;
}
static int __init prsyms2_init(void)
{
int ret;
ret = misc_register(&prsyms2_misc);
if (ret)
return ret;
symbols.pos = 0;
symbols.buf = vmalloc(SYMBOLS_BUF_SIZE);
if (symbols.buf == NULL) {
ret = -ENOMEM;
goto err1;
}
dev_info(prsyms2_misc.this_device, "Populating symbols buffer...\n");
ret = kallsyms_on_each_symbol(prsyms2_store_symbol, &symbols);
if (ret != 0) {
ret = -EINVAL;
goto err2;
}
symbols.buf[symbols.pos] = '\0';
dev_info(prsyms2_misc.this_device, "Symbols buffer is ready!\n");
return 0;
err2:
vfree(symbols.buf);
err1:
misc_deregister(&prsyms2_misc);
return ret;
}
static void __exit prsyms2_exit(void)
{
vfree(symbols.buf);
misc_deregister(&prsyms2_misc);
}
module_init(prsyms2_init);
module_exit(prsyms2_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
And here is how to use it:
$ sudo insmod prsyms2.ko
$ sudo cat /dev/prsyms2 >symbols.txt
$ wc -l symbols.txt
$ sudo rmmod prsyms2
File symbols.txt will contain all kernel symbols (both built-in and from loaded modules) in next format:
ffffffffc01dc0d0 psmouse_poll+0x0/0x30 [psmouse]
It seems that I can use kallsyms_lookup_name() to find the address of the function, can then use a function pointer to call the function?
Yes, you can. If I recall correctly, it's called reflection. Below is an example how to do so:
typedef int (*custom_print)(const char *fmt, ...);
custom_print my_print;
my_print = (custom_print)kallsyms_lookup_name("printk");
if (my_print == 0) {
pr_err("Unable to find printk\n");
return -EINVAL;
}
my_print(KERN_INFO "### printk found!\n");

Difference between '-std' and '--std' compiler flags

I've noticed that both -std and --std works for setting the standard for compiling. What is the difference between using a - and -- before std?
I've googled and found this, but it doesn't seem to mention anything about a single hyphen vs a double hyphen before a std.
-std=c99 is ok but -std c99 is an error. --std c99 is valid as is --std=c99. That's the only difference.
You can see that they map to the same action in opts-common.c:
struct option_map
{
/* Prefix of the option on the command line. */
const char *opt0;
/* If two argv elements are considered to be merged into one option,
prefix for the second element, otherwise NULL. */
const char *opt1;
/* The new prefix to map to. */
const char *new_prefix;
/* Whether at least one character is needed following opt1 or opt0
for this mapping to be used. (--optimize= is valid for -O, but
--warn- is not valid for -W.) */
bool another_char_needed;
/* Whether the original option is a negated form of the option
resulting from this map. */
bool negated;
};
static const struct option_map option_map[] =
{
...
{ "--std=", NULL, "-std=", false, false },
{ "--std", "", "-std=", false, false },
...
};

How can add my own hash(digest) algorithm to openssl

I want to use my own hash algorithm in openvpn config. I think I should define it in openssl (library), and I look at MD5 algorithm as an example to see how it is defined. I did something like what is done for MD5 but my algorithm isn't added yet! I check this using command "openvpn --show-digests". can you refer me to some document about this?I added "m_myhash.c" in crypto/evp/m_myhash.c (like m_md5.c)
#include <stdio.h>
#include "cryptlib.h"
#ifndef OPENSSL_NO_MD5
# include <openssl/evp.h>
# include <openssl/objects.h>
# include <openssl/x509.h>
# include <openssl/md5.h>
# ifndef OPENSSL_NO_RSA
# include <openssl/rsa.h>
# endif
# include "evp_locl.h"
static int init(EVP_MD_CTX *ctx)
{
return MD5_Init(ctx->md_data);
}
static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
return MD5_Update(ctx->md_data, data, count);
}
static int final(EVP_MD_CTX *ctx, unsigned char *md)
{
return MD5_Final(md, ctx->md_data);
}
static const EVP_MD myhash_md = {
NID_md5,
NID_md5WithRSAEncryption,
MD5_DIGEST_LENGTH,
0,
init,
update,
final,
NULL,
NULL,
EVP_PKEY_RSA_method,
MD5_CBLOCK,
sizeof(EVP_MD *) + sizeof(MD5_CTX),
};
const EVP_MD *EVP_myhash(void)
{
return (&myhash_md);
}
#endif
I did not changed functions already, I used md5's functions.(I want to understand defining a new hash algorithm how and where should be done and be compiled, so for now I use md5's init,update, ...)
I added lines to crypto/evp/Makefile to compile m_myhash.c and its object file is produced.
then I added this EVP_add_digest(EVP_myhash());
void OpenSSL_add_all_digests(void)
{
#ifndef OPENSSL_NO_MD4
EVP_add_digest(EVP_md4());
#endif
#ifndef OPENSSL_NO_MD5
EVP_add_digest(EVP_md5());
EVP_add_digest_alias(SN_md5, "ssl2-md5");
EVP_add_digest_alias(SN_md5, "ssl3-md5");
EVP_add_digest(EVP_myhash());
#endif
...
}
to this file crypto/evp/c_alld.c.
I added this
#define SN_myhash "MYHASH"
#define LN_myhash "myhash"
#define NID_myhash 920
#define OBJ_myhash OBJ_rsadsi,2L,5L
to file crypto/evp/c_alld.c. (here also last line is same as md5,I'm not sure about this!)
I added
920, /* OBJ_gholi 1 2 840 113549 2 5 */
I added this line
920, /* OBJ_gholi 1 2 840 113549 2 5 */
to file crypto/objects/obj_dat.h
I added {"MYHASH","myhash",NID_myhash,8,&(lvalues[5973]),0}, to this structure in file crypto/objects/obj_dat.h
static const ASN1_OBJECT nid_objs[NUM_NID]={
{"UNDEF","undefined",NID_undef,0,NULL,0},
{"rsadsi","RSA Data Security, Inc.",NID_rsadsi,6,&(lvalues[0]),0},
{"pkcs","RSA Data Security, Inc. PKCS",NID_pkcs,7,&(lvalues[6]),0},
{"MD2","md2",NID_md2,8,&(lvalues[13]),0},
{"MD5","md5",NID_md5,8,&(lvalues[21]),0},
{"MYHASH","myhash",NID_myhash,8,&(lvalues[5973]),0},
{"RC4","rc4",NID_rc4,8,&(lvalues[29]),0},
...
}
I added this
gholi 920
to file crypto/objects/obj_mac.num
also added
const EVP_MD *EVP_gholi(void);
to file crypto/evp/evp.h
I'm completely new to openssl code, I'm pretty sure I may have done blind and stupid things, sorry for that!
I find the answer, I defined a new engine like gost (engines/ccgost) and defined e new digest using MD_DIGEST EVP struct (can get help from gost digest algorithm: engines/ccgost/gost_md.c ). then I load my engine and used its digest algorithm.
for more detail one can see this Introduce GOST R 34.11-2012 hash function as an example.

Symbolic errno to String

Is there a command-line tool that will take a symbolic errno such as EINVAL and print the corresponding string, Invalid argument?
I would like to avoid having to find that EINVAL is value 22 on my system and then using$ perror 22.
Ideally I could write something like
$ errorcommand EINVAL
Invalid argument
$
AFAIK, there isn't a standard tool that does the job. At one level, it wouldn't be particularly hard to write one - the messiest parts are finding the correct file to parse (is is often, but by no means always, /usr/include/sys/errno.h) and then taking the data from that to do the mapping of names to numbers. I have not found a system that uses enum values rather than #define values, but it is probably only a matter of time. It is also a moot point whether to generate a triple consisting of token number (EINTR, etc), token name ("EINTR", etc) and error message ("Interrupted system call", etc), or whether to use just the number and name and leave it to 'strerror()' to supply the message.
As I said, it isn't particularly hard. I already had a program called 'errno' that accepted pure numeric values and printed the corresponding error messages:
$ 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
$
I've written a Perl script and hacked the program to handle symbolic error numbers too:
$ 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
$
It does not handle ranges of symbolic error numbers (exercise for the reader).
generrno.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);
}
The code needs some supporting files - stderr.h, range.h, range2.c and stderrmin.c (a simpler version of the stderr.c I normally use, which has extra bells and whistles for handling syslog and writing to file descriptors instead of file pointers.).
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 */
stderrmin.c
This is about 400 lines, instead of about 700 lines. Yes, it is overkill for this program; I don't use it only in this program.
/*
#(#)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
At least for Ubuntu (12.04 and later, to my certain knowledge), there's an errno utility you can easily install via apt-get install moreutils. (Thanks to #kevinoid and #leo for the update.)
$ errno 98
EADDRINUSE 98 Address already in use
$ errno EINVAL
EINVAL 22 Invalid argument
This works on 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 */
You can also try a Python script:
import errno
from os import strerror
from sys import argv
print strerror(errno.__dict__[argv[1]]
The function
strerror()
Is possibly what you're looking for, but I don't know of a command that exposes that to any shell offhand.
MKS exposes the command line strerror
Tried
grep EINVAL /usr/include/sys/errno.h
and seen what comes back?
#! /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
Caution: As this script uses the location of ERROR MACROS,this might not be portable although it works on my system.
Rob Wells is partially correct. Unfortunately /usr/include/asm/errno.h is nonstandard. You really need to grep /usr/include/errno.h and /usr/include/*/errno.h.
To make this errorcommand, try adding this to your .bashrc file:
function errorcommand
{
grep "${1}" /usr/include/errno.h /usr/include/*/errno.h
}
Which works like this:
Rob Wells is partially correct. Unfortunately /usr/include/asm/errno.h is nonstandard. You really need to grep /usr/include/errno.h and /usr/include/*/errno.h.
To make this errorcommand, try adding this to your .bashrc file:
function errorcommand
{
grep "${1}" /usr/include/errno.h /usr/include/*/errno.h
}
Which works like this:
$ errorcommand EINV
/usr/include/sys/errno.h:#define EINVAL 22 /* Invalid argument */
$
A compact bash script that exactly does what you want:
#!/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
On my corporate box /usr/include wasn't available. So I put this portable simple solution (if you have Python) into my init files. You can torture it into a one-liner if you wish:
function strerror () {
python -c "import os, errno; print(os.strerror(errno.$1))"
}
There's no standard utility to do this. I believe your best bet is to write such a utility yourself. Use strerror() to print the associated error message.
For people that want a quick, on-liner:
find /usr/include/ -name errno*.h -exec grep ERRNO {} +
e.g.
[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 */
Here is a short C++ program that handles both numeric and symbolic errors. Given the option -l as its very first argument, it lists all known error symbols and then exits. Otherwise iterates over all arguments and prints the error text, and nothing else, for each argument.
There is nothing much here that has not been mentioned earlier, but it does it all in a single source file, not counting table.h, which is generated.
To build:
./table.sh > table.h
g++ -O2 -Wall -W -Wextra -o errno errno.cc
The program is in C, except for the C++ iteration in list_and_exit().
errno.cc
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <errno.h>
# include <ctype.h>
struct ErrSym {
char const *name;
unsigned char value; // 0..255
};
static ErrSym const es[] = {
# include "table.h"
};
static int cmp(char const *a, ErrSym const *b) {
return strcmp(a, b->name);
}
static ErrSym const *find_by_name(char *needle) {
typedef int (*IVV)(void const *, void const *);
static int const n = (sizeof es / sizeof *es);
return (ErrSym*)bsearch(needle, es, n,
sizeof *es, (IVV)cmp);
}
static void list_and_exit() {
for (auto &e : es)
printf("%3d %-15s %s\n",
e.value, e.name, strerror(e.value));
exit(0);
}
static void handle_arg(char *arg) {
if (isdigit(arg[0]))
printf("%s\n", strerror(atoi(arg)));
else if (ErrSym const *p = find_by_name(arg))
printf("%s\n", strerror(p->value));
else
printf("Unknown error symbol: %s\n", arg);
}
int main(int argc, char *argv[]) {
if (argc > 1 && 0 == strcmp("-l", argv[1]))
list_and_exit();
for (int i = 1; i < argc; i++)
handle_arg(argv[i]);
return 0;
}
With the assumption that error numbers are less than 256, ErrSym.value is defined as unsigned char, so that the compiler can warn about values that are out of range.
To generate table.h, the trick (as mentioned in a comment above) is to use the C compiler and the preprocessor.
table.sh
#!/bin/bash
trap 'rm -f tmp.c' EXIT
echo '#include <errno.h>' > tmp.c
#
# -E Run the preprocessor only
# -dM At end, dump preprocessor symbols
# According to documentation, but not tested, these
# options should work also with clang and Intel's icc.
gcc -E -dM tmp.c | ./table.pl | sort
table.pl
#!/usr/bin/perl -n
#
# Convert '#define EACCES 13' to '{ "EACCES", 13 },'
# Skip lines that do not match
#
# By happy concidence, all names beginning
# with E are error numbers
#
next unless (/^#define +(E\S+) +(\S+)/);
$_ = sprintf("{%-18s %10s},\n", qq{"$1",}, $2);
s/, /, /; # Remove excess whitespace
print;
The output from errno -l is sorted by error symbol. Say errno -l | sort to sort by error number.

Resources