From d9ce876ea97d59d66c8d2892b43b7cc8392470a0 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 9 Jun 2012 15:37:20 +0930 Subject: ccan: import err module.from ccan revision 5add556a1cb64b49a664506aa76216d885b22c97 This allows us to avoid err.h in failtest. Signed-off-by: Rusty Russell --- lib/ccan/err/.depends | 1 + lib/ccan/err/_info | 41 +++++++++++++ lib/ccan/err/err.c | 64 ++++++++++++++++++++ lib/ccan/err/err.h | 87 +++++++++++++++++++++++++++ lib/ccan/err/test/run.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ccan/wscript | 4 +- 6 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 lib/ccan/err/.depends create mode 100644 lib/ccan/err/_info create mode 100644 lib/ccan/err/err.c create mode 100644 lib/ccan/err/err.h create mode 100644 lib/ccan/err/test/run.c diff --git a/lib/ccan/err/.depends b/lib/ccan/err/.depends new file mode 100644 index 0000000000..ee4f1e44d5 --- /dev/null +++ b/lib/ccan/err/.depends @@ -0,0 +1 @@ +ccan/compiler diff --git a/lib/ccan/err/_info b/lib/ccan/err/_info new file mode 100644 index 0000000000..97bc0f9ed4 --- /dev/null +++ b/lib/ccan/err/_info @@ -0,0 +1,41 @@ +#include +#include +#include "config.h" + +/** + * err - err(), errx(), warn() and warnx(), as per BSD's err.h. + * + * A few platforms don't provide err.h; for those, this provides replacements. + * For most, it simple includes the system err.h. + * + * Unfortunately, you have to call err_set_progname() to tell the replacements + * your program name, otherwise it prints "unknown program". + * + * Example: + * #include + * + * int main(int argc, char *argv[]) + * { + * err_set_progname(argv[0]); + * if (argc != 1) + * errx(1, "Expect no arguments"); + * exit(0); + * } + * + * License: Public domain + * Author: Rusty Russell + */ +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { +#if !HAVE_ERR_H + printf("ccan/compiler\n"); +#endif + return 0; + } + + return 1; +} diff --git a/lib/ccan/err/err.c b/lib/ccan/err/err.c new file mode 100644 index 0000000000..9e0e20c86f --- /dev/null +++ b/lib/ccan/err/err.c @@ -0,0 +1,64 @@ +#include "err.h" + +#if !HAVE_ERR_H +#include +#include +#include +#include +#include + +static const char *progname = "unknown program"; + +void err_set_progname(const char *name) +{ + progname = name; +} + +void NORETURN err(int eval, const char *fmt, ...) +{ + int err_errno = errno; + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(err_errno)); + exit(eval); +} + +void NORETURN errx(int eval, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(eval); +} + +void warn(const char *fmt, ...) +{ + int err_errno = errno; + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(err_errno)); +} + +void warnx(const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} +#endif diff --git a/lib/ccan/err/err.h b/lib/ccan/err/err.h new file mode 100644 index 0000000000..58ad91c728 --- /dev/null +++ b/lib/ccan/err/err.h @@ -0,0 +1,87 @@ +#ifndef CCAN_ERR_H +#define CCAN_ERR_H +#include "config.h" + +#if HAVE_ERR_H +#include + +/* This is unnecessary with a real err.h. See below */ +#define err_set_progname(name) ((void)name) + +#else +#include + +/** + * err_set_progname - set the program name + * @name: the name to use for err, errx, warn and warnx + * + * The BSD err.h calls know the program name, unfortunately there's no + * portable way for the CCAN replacements to do that on other systems. + * + * If you don't call this with argv[0], it will be "unknown program". + * + * Example: + * err_set_progname(argv[0]); + */ +void err_set_progname(const char *name); + +/** + * err - exit(eval) with message based on format and errno. + * @eval: the exit code + * @fmt: the printf-style format string + * + * The format string is printed to stderr like so: + * : : \n + * + * Example: + * char *p = strdup("hello"); + * if (!p) + * err(1, "Failed to strdup 'hello'"); + */ +void NORETURN err(int eval, const char *fmt, ...); + +/** + * errx - exit(eval) with message based on format. + * @eval: the exit code + * @fmt: the printf-style format string + * + * The format string is printed to stderr like so: + * : \n + * + * Example: + * if (argc != 1) + * errx(1, "I don't expect any arguments"); + */ +void NORETURN errx(int eval, const char *fmt, ...); + +/** + * warn - print a message to stderr based on format and errno. + * @eval: the exit code + * @fmt: the printf-style format string + * + * The format string is printed to stderr like so: + * : : \n + * + * Example: + * char *p = strdup("hello"); + * if (!p) + * warn("Failed to strdup 'hello'"); + */ +void warn(const char *fmt, ...); + +/** + * warnx - print a message to stderr based on format. + * @eval: the exit code + * @fmt: the printf-style format string + * + * The format string is printed to stderr like so: + * : \n + * + * Example: + * if (argc != 1) + * warnx("I don't expect any arguments (ignoring)"); + */ +void warnx(const char *fmt, ...); +#endif + +#endif /* CCAN_ERR_H */ diff --git a/lib/ccan/err/test/run.c b/lib/ccan/err/test/run.c new file mode 100644 index 0000000000..242e93f806 --- /dev/null +++ b/lib/ccan/err/test/run.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_MAX 1024 + +int main(int argc, char *argv[]) +{ + int pfd[2]; + const char *base; + + plan_tests(24); + + err_set_progname(argv[0]); + + /* In case it only prints out the basename of argv[0]. */ + base = strrchr(argv[0], '/'); + if (base) + base++; + else + base = argv[0]; + + /* Test err() in child */ + pipe(pfd); + fflush(stdout); + if (fork()) { + char buffer[BUFFER_MAX+1]; + unsigned int i; + int status; + + /* We are parent. */ + close(pfd[1]); + for (i = 0; i < BUFFER_MAX; i++) { + if (read(pfd[0], buffer + i, 1) == 0) { + buffer[i] = '\0'; + ok1(strstr(buffer, "running err:")); + ok1(strstr(buffer, strerror(ENOENT))); + ok1(strstr(buffer, base)); + ok1(buffer[i-1] == '\n'); + break; + } + } + close(pfd[0]); + ok1(wait(&status) != -1); + ok1(WIFEXITED(status)); + ok1(WEXITSTATUS(status) == 17); + } else { + close(pfd[0]); + dup2(pfd[1], STDERR_FILENO); + errno = ENOENT; + err(17, "running %s", "err"); + abort(); + } + + /* Test errx() in child */ + pipe(pfd); + fflush(stdout); + if (fork()) { + char buffer[BUFFER_MAX+1]; + unsigned int i; + int status; + + /* We are parent. */ + close(pfd[1]); + for (i = 0; i < BUFFER_MAX; i++) { + if (read(pfd[0], buffer + i, 1) == 0) { + buffer[i] = '\0'; + ok1(strstr(buffer, "running errx\n")); + ok1(strstr(buffer, base)); + break; + } + } + close(pfd[0]); + ok1(wait(&status) != -1); + ok1(WIFEXITED(status)); + ok1(WEXITSTATUS(status) == 17); + } else { + close(pfd[0]); + dup2(pfd[1], STDERR_FILENO); + errx(17, "running %s", "errx"); + abort(); + } + + + /* Test warn() in child */ + pipe(pfd); + fflush(stdout); + if (fork()) { + char buffer[BUFFER_MAX+1]; + unsigned int i; + int status; + + /* We are parent. */ + close(pfd[1]); + for (i = 0; i < BUFFER_MAX; i++) { + if (read(pfd[0], buffer + i, 1) == 0) { + buffer[i] = '\0'; + ok1(strstr(buffer, "running warn:")); + ok1(strstr(buffer, strerror(ENOENT))); + ok1(strstr(buffer, base)); + ok1(buffer[i-1] == '\n'); + break; + } + } + close(pfd[0]); + ok1(wait(&status) != -1); + ok1(WIFEXITED(status)); + ok1(WEXITSTATUS(status) == 17); + } else { + close(pfd[0]); + dup2(pfd[1], STDERR_FILENO); + errno = ENOENT; + warn("running %s", "warn"); + exit(17); + } + + /* Test warnx() in child */ + pipe(pfd); + fflush(stdout); + if (fork()) { + char buffer[BUFFER_MAX+1]; + unsigned int i; + int status; + + /* We are parent. */ + close(pfd[1]); + for (i = 0; i < BUFFER_MAX; i++) { + if (read(pfd[0], buffer + i, 1) == 0) { + buffer[i] = '\0'; + ok1(strstr(buffer, "running warnx\n")); + ok1(strstr(buffer, base)); + break; + } + } + close(pfd[0]); + ok1(wait(&status) != -1); + ok1(WIFEXITED(status)); + ok1(WEXITSTATUS(status) == 17); + } else { + close(pfd[0]); + dup2(pfd[1], STDERR_FILENO); + warnx("running %s", "warnx"); + exit(17); + } + return exit_status(); +} + diff --git a/lib/ccan/wscript b/lib/ccan/wscript index 8a2b3e79b7..24c9550121 100644 --- a/lib/ccan/wscript +++ b/lib/ccan/wscript @@ -122,14 +122,14 @@ def configure(conf): def build(bld): - for ccan_dir in ["hash", "htable", "ilog", "likely", "list", "read_write_all", "str", "tally", "time"]: + for ccan_dir in ["err", "hash", "htable", "ilog", "likely", "list", "read_write_all", "str", "tally", "time"]: bld.SAMBA_SUBSYSTEM('ccan-%s' % ccan_dir, source=bld.path.ant_glob('%s/*.c' % ccan_dir)) if bld.env.DEVELOPER_MODE: bld.SAMBA_LIBRARY('ccan-failtest', source=bld.path.ant_glob('failtest/*.c'), - deps='execinfo ccan ccan-failtest ccan-htable ccan-list ccan-read_write_all ccan-time', + deps='execinfo ccan ccan-err ccan-htable ccan-list ccan-read_write_all ccan-time', private_library=True) bld.SAMBA_LIBRARY('ccan', -- cgit