From 378c18e5f024ac5a8aef4cb40d7c9aa9633d144c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 16:30:35 +0200 Subject: Adding upstream version 2.38.1. Signed-off-by: Daniel Baumann --- tests/helpers/Makemodule.am | 37 ++ tests/helpers/test_byteswap.c | 114 ++++++ tests/helpers/test_mbsencode.c | 52 +++ tests/helpers/test_md5.c | 29 ++ tests/helpers/test_mkfds.c | 775 ++++++++++++++++++++++++++++++++++++ tests/helpers/test_pathnames.c | 86 ++++ tests/helpers/test_sha1.c | 29 ++ tests/helpers/test_sigreceive.c | 181 +++++++++ tests/helpers/test_strerror.c | 45 +++ tests/helpers/test_sysinfo.c | 138 +++++++ tests/helpers/test_tiocsti.c | 32 ++ tests/helpers/test_uuid_namespace.c | 37 ++ 12 files changed, 1555 insertions(+) create mode 100644 tests/helpers/Makemodule.am create mode 100644 tests/helpers/test_byteswap.c create mode 100644 tests/helpers/test_mbsencode.c create mode 100644 tests/helpers/test_md5.c create mode 100644 tests/helpers/test_mkfds.c create mode 100644 tests/helpers/test_pathnames.c create mode 100644 tests/helpers/test_sha1.c create mode 100644 tests/helpers/test_sigreceive.c create mode 100644 tests/helpers/test_strerror.c create mode 100644 tests/helpers/test_sysinfo.c create mode 100644 tests/helpers/test_tiocsti.c create mode 100644 tests/helpers/test_uuid_namespace.c (limited to 'tests/helpers') diff --git a/tests/helpers/Makemodule.am b/tests/helpers/Makemodule.am new file mode 100644 index 0000000..83df24b --- /dev/null +++ b/tests/helpers/Makemodule.am @@ -0,0 +1,37 @@ +check_PROGRAMS += test_mbsencode +test_mbsencode_SOURCES = tests/helpers/test_mbsencode.c +test_mbsencode_LDADD = $(LDADD) libcommon.la + +check_PROGRAMS += test_byteswap +test_byteswap_SOURCES = tests/helpers/test_byteswap.c + +check_PROGRAMS += test_md5 +test_md5_SOURCES = tests/helpers/test_md5.c lib/md5.c + +check_PROGRAMS += test_sha1 +test_sha1_SOURCES = tests/helpers/test_sha1.c lib/sha1.c + +check_PROGRAMS += test_pathnames +test_pathnames_SOURCES = tests/helpers/test_pathnames.c + +check_PROGRAMS += test_strerror +test_strerror_SOURCES = tests/helpers/test_strerror.c + +check_PROGRAMS += test_sysinfo +test_sysinfo_SOURCES = tests/helpers/test_sysinfo.c + +check_PROGRAMS += test_sigreceive +test_sigreceive_SOURCES = tests/helpers/test_sigreceive.c +test_sigreceive_LDADD = $(LDADD) libcommon.la + +check_PROGRAMS += test_tiocsti +test_tiocsti_SOURCES = tests/helpers/test_tiocsti.c + +check_PROGRAMS += test_uuid_namespace +test_uuid_namespace_SOURCES = tests/helpers/test_uuid_namespace.c \ + libuuid/src/predefined.c libuuid/src/unpack.c libuuid/src/unparse.c + +if LINUX +check_PROGRAMS += test_mkfds +test_mkfds_SOURCES = tests/helpers/test_mkfds.c +endif diff --git a/tests/helpers/test_byteswap.c b/tests/helpers/test_byteswap.c new file mode 100644 index 0000000..1b98f76 --- /dev/null +++ b/tests/helpers/test_byteswap.c @@ -0,0 +1,114 @@ +/* + * This testing program makes sure the byteswap functions work + * + * Copyright (C) 2000 by Theodore Ts'o. + * Copyright (C) 2008 Karel Zak + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bitops.h" + +static uint16_t ary16[] = { + 0x0001, 0x0100, + 0x1234, 0x3412, + 0xff00, 0x00ff, + 0x4000, 0x0040, + 0xfeff, 0xfffe, + 0x0000, 0x0000 + }; + +static uint32_t ary32[] = { + 0x00000001, 0x01000000, + 0x80000000, 0x00000080, + 0x12345678, 0x78563412, + 0xffff0000, 0x0000ffff, + 0x00ff0000, 0x0000ff00, + 0xff000000, 0x000000ff, + 0x00000000, 0x00000000 + }; + +static uint64_t ary64[] = { + 0x0000000000000001, 0x0100000000000000, + 0x8000000000000000, 0x0000000000000080, + 0x1234567812345678, 0x7856341278563412, + 0xffffffff00000000, 0x00000000ffffffff, + 0x00ff000000000000, 0x000000000000ff00, + 0xff00000000000000, 0x00000000000000ff, + 0x0000000000000000, 0x0000000000000000 + }; + +int main(void) +{ + int i; + int errors = 0; + + printf("Testing swab16\n"); + i=0; + do { + printf("swab16(0x%04"PRIx16") = 0x%04"PRIx16"\n", + ary16[i], swab16(ary16[i])); + if (swab16(ary16[i]) != ary16[i+1]) { + printf("Error!!! %04"PRIx16" != %04"PRIx16"\n", + swab16(ary16[i]), ary16[i+1]); + errors++; + } + if (swab16(ary16[i+1]) != ary16[i]) { + printf("Error!!! %04"PRIx16" != %04"PRIx16"\n", + swab16(ary16[i+1]), ary16[i]); + errors++; + } + i += 2; + } while (ary16[i] != 0); + + printf("Testing swab32\n"); + i = 0; + do { + printf("swab32(0x%08"PRIx32") = 0x%08"PRIx32"\n", + ary32[i], swab32(ary32[i])); + if (swab32(ary32[i]) != ary32[i+1]) { + printf("Error!!! %04"PRIx32" != %04"PRIx32"\n", + swab32(ary32[i]), ary32[i+1]); + errors++; + } + if (swab32(ary32[i+1]) != ary32[i]) { + printf("Error!!! %04"PRIx32" != %04"PRIx32"\n", + swab32(ary32[i+1]), ary32[i]); + errors++; + } + i += 2; + } while (ary32[i] != 0); + + printf("Testing swab64\n"); + i = 0; + do { + printf("swab64(0x%016"PRIx64") = 0x%016"PRIx64"\n", + ary64[i], swab64(ary64[i])); + if (swab64(ary64[i]) != ary64[i+1]) { + printf("Error!!! %016"PRIx64" != %016"PRIx64"\n", + swab64(ary64[i]), ary64[i+1]); + errors++; + } + if (swab64(ary64[i+1]) != ary64[i]) { + printf("Error!!! %016"PRIx64" != %016"PRIx64"\n", + swab64(ary64[i+1]), ary64[i]); + errors++; + } + i += 2; + } while (ary64[i] != 0); + + if (!errors) + printf("No errors found in the byteswap implementation\n"); + + return errors; +} diff --git a/tests/helpers/test_mbsencode.c b/tests/helpers/test_mbsencode.c new file mode 100644 index 0000000..a8f9383 --- /dev/null +++ b/tests/helpers/test_mbsencode.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Vaclav Dolezal + * + * This file is part of util-linux. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "mbsalign.h" + +int main(int argc, char **argv) +{ + int i = 1; + char *(*encode_fn)(const char *, size_t *) = mbs_safe_encode; + + setlocale(LC_ALL, ""); + + if (i < argc) { + if (!strcmp(argv[i], "--safe")) { + i++; + encode_fn = mbs_safe_encode; + } else if (!strcmp(argv[i], "--invalid")) { + i++; + encode_fn = mbs_invalid_encode; + } else if (!strcmp(argv[i], "--")) { + i++; + } + } + + for (; i < argc; i++) { + size_t width; + char *res; + res = encode_fn(argv[i], &width); + printf("%zi %s\n", width, res); + free(res); + } + + return 0; +} diff --git a/tests/helpers/test_md5.c b/tests/helpers/test_md5.c new file mode 100644 index 0000000..6f8dec4 --- /dev/null +++ b/tests/helpers/test_md5.c @@ -0,0 +1,29 @@ + +#include +#include + +#include "md5.h" + +int main(void) +{ + int i, ret; + struct UL_MD5Context ctx; + unsigned char digest[UL_MD5LENGTH]; + unsigned char buf[BUFSIZ]; + + ul_MD5Init( &ctx ); + + while(!feof(stdin) && !ferror(stdin)) { + ret = fread(buf, 1, sizeof(buf), stdin); + if (ret) + ul_MD5Update( &ctx, buf, ret ); + } + + fclose(stdin); + ul_MD5Final( digest, &ctx ); + + for (i = 0; i < UL_MD5LENGTH; i++) + printf( "%02x", digest[i] ); + printf("\n"); + return 0; +} diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c new file mode 100644 index 0000000..12b814f --- /dev/null +++ b/tests/helpers/test_mkfds.c @@ -0,0 +1,775 @@ +/* + * test_lsfd - make various file descriptors + * + * Written by Masatake YAMATO + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "c.h" +#include "nls.h" +#include "xalloc.h" + +#define _U_ __attribute__((__unused__)) + +static void __attribute__((__noreturn__)) usage(FILE *out, int status) +{ + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options] FACTORY FD... [PARAM=VAL...]\n"), program_invocation_short_name); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -l, --list list available file descriptor factories and exit\n"), out); + fputs(_(" -I, --parameters list parameters the factory takes\n"), out); + fputs(_(" -r, --comm rename self\n"), out); + fputs(_(" -q, --quiet don't print pid(s)\n"), out); + fputs(_(" -c, --dont-pause don't pause after making fd(s)\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Examples:\n"), out); + fprintf(out, _("Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n"), + program_invocation_short_name); + fprintf(out, _("Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n"), + program_invocation_short_name); + + exit(status); +} + +union value { + const char *string; + long integer; +}; + +enum ptype { + PTYPE_STRING, + PTYPE_INTEGER, +}; + +struct ptype_class { + const char *name; + + /* Covert to a string representation. + * A caller must free the returned value with free(3) after using. */ + char *(*sprint)(const union value *value); + + /* Convert from a string. If ARG is NULL, use DEFV instead. + * A caller must free the returned value with the free method + * after using. */ + union value (*read)(const char *arg, const union value *defv); + + /* Free the value returned from the read method. */ + void (*free)(union value value); +}; + +#define ARG_STRING(A) (A.v.string) +#define ARG_INTEGER(A) (A.v.integer) +struct arg { + union value v; + void (*free)(union value value); +}; + +struct parameter { + const char *name; + const enum ptype type; + const char *desc; + union value defv; /* Default value */ +}; + +static char *string_sprint(const union value *value) +{ + return xstrdup(value->string); +} + +static union value string_read(const char *arg, const union value *defv) +{ + return (union value){ .string = xstrdup(arg?: defv->string) }; +} + +static void string_free(union value value) +{ + free((void *)value.string); +} + +static char *integer_sprint(const union value *value) +{ + char *str = NULL; + xasprintf(&str, "%ld", value->integer); + return str; +} + +static union value integer_read(const char *arg, const union value *defv) +{ + char *ep; + union value r; + + if (!arg) + return *defv; + + errno = 0; + r.integer = strtol(arg, &ep, 10); + if (errno) + err(EXIT_FAILURE, _("fail to make a number from %s"), arg); + else if (*ep != '\0') + errx(EXIT_FAILURE, _("garbage at the end of number: %s"), arg); + return r; +} + +static void integer_free(union value value _U_) +{ + /* Do nothing */ +} + + +struct ptype_class ptype_classes [] = { + [PTYPE_STRING] = { + .name = "string", + .sprint = string_sprint, + .read = string_read, + .free = string_free, + }, + [PTYPE_INTEGER] = { + .name = "integer", + .sprint = integer_sprint, + .read = integer_read, + .free = integer_free, + }, +}; + +static struct arg decode_arg(const char *pname, + const struct parameter *parameters, + int argc, char **argv) +{ + char *v = NULL; + size_t len = strlen(pname); + const struct parameter *p = NULL; + struct arg arg; + + while (parameters->name) { + if (strcmp(pname, parameters->name) == 0) { + p = parameters; + break; + } + parameters++; + } + if (p == NULL) + errx(EXIT_FAILURE, _("no such parameter: %s"), pname); + + for (int i = 0; i < argc; i++) { + if (strncmp(pname, argv[i], len) == 0) { + v = argv[i] + len; + if (*v == '=') { + v++; + break; + } else if (*v == '\0') + errx(EXIT_FAILURE, + _("no value given for \"%s\" parameter"), + pname); + else + v = NULL; + } + } + arg.v = ptype_classes [p->type].read (v, &p->defv); + arg.free = ptype_classes [p->type].free; + return arg; +} + +static void free_arg(struct arg *arg) +{ + arg->free(arg->v); +} + +struct fdesc { + int fd; + void (*close)(int, void *); + void *data; +}; + +struct factory { + const char *name; /* [-a-zA-Z0-9_]+ */ + const char *desc; + bool priv; /* the root privilege is needed to make fd(s) */ +#define MAX_N 3 + int N; /* the number of fds this factory makes */ + bool fork; /* whether this factory make a child process or not */ + void (*make)(const struct factory *, struct fdesc[], pid_t *, int, char **); + const struct parameter * params; +}; + +static void close_fdesc(int fd, void *data _U_) +{ + close(fd); +} + +static void open_ro_regular_file(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + struct arg file = decode_arg("file", factory->params, argc, argv); + struct arg offset = decode_arg("offset", factory->params, argc, argv); + + int fd = open(ARG_STRING(file), O_RDONLY); + if (fd < 0) + err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(file)); + free_arg(&file); + + if (ARG_INTEGER(offset) != 0) { + if (lseek(fd, (off_t)ARG_INTEGER(offset), SEEK_CUR) < 0) { + int e = errno; + close(fd); + errno = e; + err(EXIT_FAILURE, "failed to seek 0 -> %ld", ARG_INTEGER(offset)); + } + } + free_arg(&offset); + + if (fd != fdescs[0].fd) { + if (dup2(fd, fdescs[0].fd) < 0) { + int e = errno; + close(fd); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd); + } + close(fd); + } + + fdescs[0] = (struct fdesc){ + .fd = fdescs[0].fd, + .close = close_fdesc, + .data = NULL + }; +} + +static void make_pipe(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + int pd[2]; + int nonblock_flags[2] = {0, 0}; + struct arg nonblock = decode_arg("nonblock", factory->params, argc, argv); + if (strlen(ARG_STRING(nonblock)) != 2) { + errx(EXIT_FAILURE, "string value for %s has unexpected length: %s", + "nonblock", ARG_STRING(nonblock)); + } + + for (int i = 0; i < 2; i++) { + if (ARG_STRING(nonblock)[i] == '-') + continue; + if ((i == 0 && ARG_STRING(nonblock)[i] == 'r') + || (i == 1 && ARG_STRING(nonblock)[i] == 'w')) + nonblock_flags[i] = 1; + else + errx(EXIT_FAILURE, "unexpected value %c for the %s fd of %s", + ARG_STRING(nonblock)[i], + (i == 0)? "read": "write", + "nonblock"); + } + free_arg(&nonblock); + + if (pipe(pd) < 0) + err(EXIT_FAILURE, "failed to make pipe"); + + for (int i = 0; i < 2; i++) { + if (nonblock_flags[i]) { + int flags = fcntl(pd[i], F_GETFL); + if (fcntl(pd[i], F_SETFL, flags|O_NONBLOCK) < 0) { + int e = errno; + close(pd[0]); + close(pd[1]); + errno = e; + errx(EXIT_FAILURE, "failed to set NONBLOCK flag to the %s fd", + (i == 0)? "read": "write"); + } + } + } + + for (int i = 0; i < 2; i++) { + if (pd[i] != fdescs[i].fd) { + if (dup2(pd[i], fdescs[i].fd) < 0) { + int e = errno; + close(pd[0]); + close(pd[1]); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", + pd[i], fdescs[i].fd); + } + close(pd[i]); + } + fdescs[i] = (struct fdesc){ + .fd = fdescs[i].fd, + .close = close_fdesc, + .data = NULL + }; + } +} + +static void close_dir(int fd, void *data) +{ + DIR *dp = data; + if (dp) + closedir(dp); + else + close_fdesc(fd, NULL); +} + +static void open_directory(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + struct arg dir = decode_arg("dir", factory->params, argc, argv); + struct arg dentries = decode_arg("dentries", factory->params, argc, argv); + DIR *dp = NULL; + + int fd = open(ARG_STRING(dir), O_RDONLY|O_DIRECTORY); + if (fd < 0) + err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(dir)); + free_arg(&dir); + + if (fd != fdescs[0].fd) { + if (dup2(fd, fdescs[0].fd) < 0) { + int e = errno; + close(fd); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd); + } + close(fd); + } + + if (ARG_INTEGER(dentries) > 0) { + dp = fdopendir(fdescs[0].fd); + if (dp == NULL) { + int e = errno; + close(fdescs[0].fd); + errno = e; + err(EXIT_FAILURE, "failed to make DIR* from fd: %s", ARG_STRING(dir)); + } + for (int i = 0; i < ARG_INTEGER(dentries); i++) { + struct dirent *d = readdir(dp); + if (!d) { + int e = errno; + closedir(dp); + errno = e; + err(EXIT_FAILURE, "failed in readdir(3)"); + } + } + } + free_arg(&dentries); + + + fdescs[0] = (struct fdesc){ + .fd = fdescs[0].fd, + .close = close_dir, + .data = dp + }; +} + +static void open_rw_chrdev(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + struct arg chrdev = decode_arg("chrdev", factory->params, argc, argv); + int fd = open(ARG_STRING(chrdev), O_RDWR); + if (fd < 0) + err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(chrdev)); + free_arg(&chrdev); + + fdescs[0] = (struct fdesc){ + .fd = fd, + .close = close_fdesc, + .data = NULL + }; +} + +static void make_socketpair(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + int sd[2]; + struct arg socktype = decode_arg("socktype", factory->params, argc, argv); + int isocktype; + if (strcmp(ARG_STRING(socktype), "STREAM") == 0) + isocktype = SOCK_STREAM; + else if (strcmp(ARG_STRING(socktype), "DGRAM") == 0) + isocktype = SOCK_DGRAM; + else if (strcmp(ARG_STRING(socktype), "SEQPACKET") == 0) + isocktype = SOCK_SEQPACKET; + else + errx(EXIT_FAILURE, + "unknown socket type for socketpair(AF_UNIX,...): %s", + ARG_STRING(socktype)); + free_arg(&socktype); + + if (socketpair(AF_UNIX, isocktype, 0, sd) < 0) + err(EXIT_FAILURE, "failed to make socket pair"); + + for (int i = 0; i < 2; i++) { + if (sd[i] != fdescs[i].fd) { + if (dup2(sd[i], fdescs[i].fd) < 0) { + int e = errno; + close(sd[0]); + close(sd[1]); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", + sd[i], fdescs[i].fd); + } + close(sd[i]); + } + fdescs[i] = (struct fdesc){ + .fd = fdescs[i].fd, + .close = close_fdesc, + .data = NULL + }; + } +} + +static void open_with_opath(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + struct arg path = decode_arg("path", factory->params, argc, argv); + int fd = open(ARG_STRING(path), O_PATH|O_NOFOLLOW); + if (fd < 0) + err(EXIT_FAILURE, "failed to open with O_PATH: %s", ARG_STRING(path)); + free_arg(&path); + + fdescs[0] = (struct fdesc){ + .fd = fd, + .close = close_fdesc, + .data = NULL + }; +} + +static void open_ro_blkdev(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_, + int argc, char ** argv) +{ + struct arg blkdev = decode_arg("blkdev", factory->params, argc, argv); + int fd = open(ARG_STRING(blkdev), O_RDONLY); + if (fd < 0) + err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(blkdev)); + free_arg(&blkdev); + + fdescs[0] = (struct fdesc){ + .fd = fd, + .close = close_fdesc, + .data = NULL, + }; +} + +#define PARAM_END { .name = NULL, } +static const struct factory factories[] = { + { + .name = "ro-regular-file", + .desc = "read-only regular file", + .priv = false, + .N = 1, + .fork = false, + .make = open_ro_regular_file, + .params = (struct parameter []) { + { + .name = "file", + .type = PTYPE_STRING, + .desc = "file to be opened", + .defv.string = "/etc/passwd", + }, + { + .name = "offset", + .type = PTYPE_INTEGER, + .desc = "seek bytes after open with SEEK_CUR", + .defv.integer = 0, + }, + PARAM_END + }, + }, + { + .name = "pipe-no-fork", + .desc = "making pair of fds with pipe(2)", + .priv = false, + .N = 2, + .fork = false, + .make = make_pipe, + .params = (struct parameter []) { + { + .name = "nonblock", + .type = PTYPE_STRING, + .desc = "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")", + .defv.string = "--", + }, + PARAM_END + }, + }, + { + .name = "directory", + .desc = "directory", + .priv = false, + .N = 1, + .fork = false, + .make = open_directory, + .params = (struct parameter []) { + { + .name = "dir", + .type = PTYPE_STRING, + .desc = "directory to be opened", + .defv.string = "/", + }, + { + .name = "dentries", + .type = PTYPE_INTEGER, + .desc = "read the number of dentries after open with readdir(3)", + .defv.integer = 0, + }, + PARAM_END + }, + }, + { + .name = "rw-character-device", + .desc = "character device with O_RDWR flag", + .priv = false, + .N = 1, + .fork = false, + .make = open_rw_chrdev, + .params = (struct parameter []) { + { + .name = "chrdev", + .type = PTYPE_STRING, + .desc = "character device node to be opened", + .defv.string = "/dev/zero", + }, + PARAM_END + }, + }, + { + .name = "socketpair", + .desc = "AF_UNIX socket pair created with socketpair(2)", + .priv = false, + .N = 2, + .fork = false, + .make = make_socketpair, + .params = (struct parameter []) { + { + .name = "socktype", + .type = PTYPE_STRING, + .desc = "STREAM, DGRAM, or SEQPACKET", + .defv.string = "STREAM", + }, + PARAM_END + }, + }, + { + .name = "symlink", + .desc = "symbolic link itself opened with O_PATH", + .priv = false, + .N = 1, + .fork = false, + .make = open_with_opath, + .params = (struct parameter []) { + { + .name = "path", + .type = PTYPE_STRING, + .desc = "path to a symbolic link", + .defv.string = "/dev/stdin", + }, + PARAM_END + }, + }, + { + .name = "ro-block-device", + .desc = "block device with O_RDONLY flag", + .priv = true, + .N = 1, + .fork = false, + .make = open_ro_blkdev, + .params = (struct parameter []) { + { + .name = "blkdev", + .type = PTYPE_STRING, + .desc = "block device node to be opened", + .defv.string = "/dev/nullb0", + }, + PARAM_END + }, + }, +}; + +static int count_parameters(const struct factory *factory) +{ + + const struct parameter *p = factory->params; + if (!p) + return 0; + while (p->name) + p++; + return p - factory->params; +} + +static void print_factory(const struct factory *factory) +{ + printf("%-20s %4s %5d %4s %6d %s\n", + factory->name, + factory->priv? "yes": "no", + factory->N, + factory->fork? "yes": "no", + count_parameters(factory), + factory->desc); +} + +static void list_factories(void) +{ + printf("%-20s PRIV COUNT FORK NPARAM DESCRIPTION\n", "FACTORY"); + for (size_t i = 0; i < ARRAY_SIZE(factories); i++) + print_factory(factories + i); +} + +static const struct factory *find_factory(const char *name) +{ + for (size_t i = 0; i < ARRAY_SIZE(factories); i++) + if (strcmp(factories[i].name, name) == 0) + return factories + i; + return NULL; +} + +static void list_parameters(const char *factory_name) +{ + const struct factory *factory = find_factory(factory_name); + const char *fmt = "%-15s %-8s %15s %s\n"; + + if (!factory) + errx(EXIT_FAILURE, _("no such factory: %s"), factory_name); + + if (!factory->params) + return; + + printf(fmt, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION"); + for (const struct parameter *p = factory->params; p->name != NULL; p++) { + char *defv = ptype_classes[p->type].sprint(&p->defv); + printf(fmt, p->name, ptype_classes[p->type].name, defv, p->desc); + free(defv); + } +} + +static void rename_self(const char *comm) +{ + if (prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0) < 0) + err(EXIT_FAILURE, _("failed to rename self via prctl: %s"), comm); +} + +static void do_nothing(int signum _U_) +{ +} + +int main(int argc, char **argv) +{ + int c; + pid_t pid[2]; + const struct factory *factory; + struct fdesc fdescs[MAX_N]; + bool quiet = false; + bool cont = false; + + pid[0] = getpid(); + pid[1] = -1; + + static const struct option longopts[] = { + { "list", no_argument, NULL, 'l' }, + { "parameters", required_argument, NULL, 'I' }, + { "comm", required_argument, NULL, 'r' }, + { "quiet", no_argument, NULL, 'q' }, + { "dont-puase", no_argument, NULL, 'c' }, + { "help", no_argument, NULL, 'h' }, + }; + + while ((c = getopt_long(argc, argv, "lhqcI:r:", longopts, NULL)) != -1) { + switch (c) { + case 'h': + usage(stdout, EXIT_SUCCESS); + case 'l': + list_factories(); + exit(EXIT_SUCCESS); + case 'I': + list_parameters(optarg); + exit(EXIT_SUCCESS); + case 'q': + quiet = true; + break; + case 'c': + cont = true; + break; + case 'r': + rename_self(optarg); + break; + default: + usage(stderr, EXIT_FAILURE); + } + } + + + if (optind == argc) + errx(EXIT_FAILURE, _("no file descriptor specification given")); + + factory = find_factory(argv[optind]); + if (!factory) + errx(EXIT_FAILURE, _("no such factory: %s"), argv[optind]); + assert(factory->N < MAX_N); + optind++; + + if ((optind + factory->N) > argc) + errx(EXIT_FAILURE, _("not enough file descriptors given for %s"), + factory->name); + for (int i = 0; i < factory->N; i++) { + char *str = argv[optind + i]; + long fd; + char *ep; + + errno = 0; + fd = strtol(str, &ep, 10); + if (errno) + err(EXIT_FAILURE, "failed to convert fd number: %s", str); + if (ep == str) + errx(EXIT_FAILURE, "failed to convert fd number: %s", str); + if (*ep != '\0') + errx(EXIT_FAILURE, _("garbage at the end of number: %s"), str); + if (fd < 0) + errx(EXIT_FAILURE, "fd number should not be negative: %s", str); + if (fd < 3) + errx(EXIT_FAILURE, "fd 0, 1, 2 are reserved: %s", str); + fdescs[i].fd = fd; + } + optind += factory->N; + + factory->make(factory, fdescs, pid + 1, argc - optind, argv + optind); + + signal(SIGCONT, do_nothing); + + if (!quiet) { + printf("%d", pid[0]); + if (pid[1] != -1) + printf(" %d", pid[1]); + putchar('\n'); + fflush(stdout); + } + + if (!cont) + pause(); + + for (int i = 0; i < factory->N; i++) + fdescs[i].close(fdescs[i].fd, fdescs[i].data); + + exit(EXIT_SUCCESS); +} diff --git a/tests/helpers/test_pathnames.c b/tests/helpers/test_pathnames.c new file mode 100644 index 0000000..2368641 --- /dev/null +++ b/tests/helpers/test_pathnames.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007 Karel Zak + * + * This file is part of util-linux. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pathnames.h" + +struct hlpPath +{ + const char *name; + const char *path; +}; + +#define DEF_HLPPATH(_p) { #_p, _p } + +static struct hlpPath paths[] = +{ + DEF_HLPPATH(_PATH_DEFPATH), + DEF_HLPPATH(_PATH_DEFPATH_ROOT), + DEF_HLPPATH(_PATH_DEV_LOOP), + DEF_HLPPATH(_PATH_HUSHLOGIN), + DEF_HLPPATH(_PATH_MAILDIR), + DEF_HLPPATH(_PATH_MOTDFILE), + DEF_HLPPATH(_PATH_NOLOGIN), + DEF_HLPPATH(_PATH_LOGIN), + DEF_HLPPATH(_PATH_PASSWD), + DEF_HLPPATH(_PATH_GSHADOW), + DEF_HLPPATH(_PATH_GROUP), + DEF_HLPPATH(_PATH_SHADOW_PASSWD), + DEF_HLPPATH(_PATH_WORDS), + DEF_HLPPATH(_PATH_WORDS_ALT), + DEF_HLPPATH(_PATH_FILESYSTEMS), + DEF_HLPPATH(_PATH_PROC_SWAPS), + DEF_HLPPATH(_PATH_PROC_FILESYSTEMS), + DEF_HLPPATH(_PATH_MOUNTED), + DEF_HLPPATH(_PATH_MNTTAB), + DEF_HLPPATH(_PATH_DEV_BYLABEL), + DEF_HLPPATH(_PATH_DEV_BYUUID), + { NULL, NULL } +}; + +int +main(int argc, char **argv) +{ + struct hlpPath *p; + + if (argc == 1) { + for (p = paths; p->name; p++) + printf("%20s %s\n", p->name, p->path); + exit(EXIT_SUCCESS); + } else { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { + printf("%s