From dbb41ce2b7f309d394054a6bd1e33afd578798a5 Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Fri, 23 Oct 2020 15:18:01 +0200 Subject: Move the source code of all xloop components to the common 'src' directory --- utils/lib/CMakeLists.txt | 44 -- utils/lib/blkdev.c | 452 ----------- utils/lib/canonicalize.c | 250 ------ utils/lib/caputils.c | 45 -- utils/lib/color-names.c | 64 -- utils/lib/colors.c | 907 --------------------- utils/lib/cpuset.c | 413 ---------- utils/lib/crc32.c | 142 ---- utils/lib/crc32c.c | 102 --- utils/lib/encode.c | 79 -- utils/lib/env.c | 238 ------ utils/lib/exec_shell.c | 51 -- utils/lib/fileutils.c | 246 ------ utils/lib/idcache.c | 117 --- utils/lib/ismounted.c | 396 ---------- utils/lib/langinfo.c | 124 --- utils/lib/linux_version.c | 71 -- utils/lib/loopdev.c | 1914 --------------------------------------------- utils/lib/mangle.c | 169 ---- utils/lib/match.c | 53 -- utils/lib/mbsalign.c | 627 --------------- utils/lib/mbsedit.c | 225 ------ utils/lib/md5.c | 257 ------ utils/lib/monotonic.c | 81 -- utils/lib/pager.c | 317 -------- utils/lib/path.c | 1248 ----------------------------- utils/lib/plymouth-ctrl.c | 144 ---- utils/lib/procutils.c | 308 -------- utils/lib/pty-session.c | 725 ----------------- utils/lib/pwdutils.c | 156 ---- utils/lib/randutils.c | 238 ------ utils/lib/setproctitle.c | 75 -- utils/lib/sha1.c | 256 ------ utils/lib/signames.c | 204 ----- utils/lib/strutils.c | 1135 --------------------------- utils/lib/strv.c | 403 ---------- utils/lib/sysfs.c | 1127 -------------------------- utils/lib/timer.c | 95 --- utils/lib/timeutils.c | 611 --------------- utils/lib/ttyutils.c | 152 ---- 40 files changed, 14261 deletions(-) delete mode 100644 utils/lib/CMakeLists.txt delete mode 100644 utils/lib/blkdev.c delete mode 100644 utils/lib/canonicalize.c delete mode 100644 utils/lib/caputils.c delete mode 100644 utils/lib/color-names.c delete mode 100644 utils/lib/colors.c delete mode 100644 utils/lib/cpuset.c delete mode 100644 utils/lib/crc32.c delete mode 100644 utils/lib/crc32c.c delete mode 100644 utils/lib/encode.c delete mode 100644 utils/lib/env.c delete mode 100644 utils/lib/exec_shell.c delete mode 100644 utils/lib/fileutils.c delete mode 100644 utils/lib/idcache.c delete mode 100644 utils/lib/ismounted.c delete mode 100644 utils/lib/langinfo.c delete mode 100644 utils/lib/linux_version.c delete mode 100644 utils/lib/loopdev.c delete mode 100644 utils/lib/mangle.c delete mode 100644 utils/lib/match.c delete mode 100644 utils/lib/mbsalign.c delete mode 100644 utils/lib/mbsedit.c delete mode 100644 utils/lib/md5.c delete mode 100644 utils/lib/monotonic.c delete mode 100644 utils/lib/pager.c delete mode 100644 utils/lib/path.c delete mode 100644 utils/lib/plymouth-ctrl.c delete mode 100644 utils/lib/procutils.c delete mode 100644 utils/lib/pty-session.c delete mode 100644 utils/lib/pwdutils.c delete mode 100644 utils/lib/randutils.c delete mode 100644 utils/lib/setproctitle.c delete mode 100644 utils/lib/sha1.c delete mode 100644 utils/lib/signames.c delete mode 100644 utils/lib/strutils.c delete mode 100644 utils/lib/strv.c delete mode 100644 utils/lib/sysfs.c delete mode 100644 utils/lib/timer.c delete mode 100644 utils/lib/timeutils.c delete mode 100644 utils/lib/ttyutils.c (limited to 'utils/lib') diff --git a/utils/lib/CMakeLists.txt b/utils/lib/CMakeLists.txt deleted file mode 100644 index e5fa459..0000000 --- a/utils/lib/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -# set the project name -project(xloop-utils-lib) - -add_library(libcommon STATIC ${CMAKE_CURRENT_SOURCE_DIR}/blkdev.c - ${CMAKE_CURRENT_SOURCE_DIR}/canonicalize.c - ${CMAKE_CURRENT_SOURCE_DIR}/caputils.c - ${CMAKE_CURRENT_SOURCE_DIR}/color-names.c - ${CMAKE_CURRENT_SOURCE_DIR}/colors.c - ${CMAKE_CURRENT_SOURCE_DIR}/cpuset.c - ${CMAKE_CURRENT_SOURCE_DIR}/crc32.c - ${CMAKE_CURRENT_SOURCE_DIR}/crc32c.c - ${CMAKE_CURRENT_SOURCE_DIR}/encode.c - ${CMAKE_CURRENT_SOURCE_DIR}/env.c - ${CMAKE_CURRENT_SOURCE_DIR}/exec_shell.c - ${CMAKE_CURRENT_SOURCE_DIR}/fileutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/idcache.c - ${CMAKE_CURRENT_SOURCE_DIR}/ismounted.c - ${CMAKE_CURRENT_SOURCE_DIR}/langinfo.c - ${CMAKE_CURRENT_SOURCE_DIR}/linux_version.c - ${CMAKE_CURRENT_SOURCE_DIR}/loopdev.c - ${CMAKE_CURRENT_SOURCE_DIR}/mangle.c - ${CMAKE_CURRENT_SOURCE_DIR}/match.c - ${CMAKE_CURRENT_SOURCE_DIR}/mbsalign.c - ${CMAKE_CURRENT_SOURCE_DIR}/mbsedit.c - ${CMAKE_CURRENT_SOURCE_DIR}/md5.c - ${CMAKE_CURRENT_SOURCE_DIR}/monotonic.c - ${CMAKE_CURRENT_SOURCE_DIR}/pager.c - ${CMAKE_CURRENT_SOURCE_DIR}/path.c - ${CMAKE_CURRENT_SOURCE_DIR}/plymouth-ctrl.c - ${CMAKE_CURRENT_SOURCE_DIR}/procutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/pty-session.c - ${CMAKE_CURRENT_SOURCE_DIR}/pwdutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/randutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/setproctitle.c - ${CMAKE_CURRENT_SOURCE_DIR}/sha1.c - ${CMAKE_CURRENT_SOURCE_DIR}/signames.c - ${CMAKE_CURRENT_SOURCE_DIR}/strutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/strv.c - ${CMAKE_CURRENT_SOURCE_DIR}/sysfs.c - ${CMAKE_CURRENT_SOURCE_DIR}/timer.c - ${CMAKE_CURRENT_SOURCE_DIR}/timeutils.c - ${CMAKE_CURRENT_SOURCE_DIR}/ttyutils.c) diff --git a/utils/lib/blkdev.c b/utils/lib/blkdev.c deleted file mode 100644 index c22853d..0000000 --- a/utils/lib/blkdev.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak - */ -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LINUX_FD_H -#include -#endif - -#ifdef HAVE_SYS_DISKLABEL_H -#include -#endif - -#ifdef HAVE_SYS_DISK_H -# include -#endif - -#ifndef EBADFD -# define EBADFD 77 /* File descriptor in bad state */ -#endif - -#include "blkdev.h" -#include "c.h" -#include "linux_version.h" -#include "fileutils.h" -#include "nls.h" - -static long -blkdev_valid_offset (int fd, off_t offset) { - char ch; - - if (lseek (fd, offset, 0) < 0) - return 0; - if (read (fd, &ch, 1) < 1) - return 0; - return 1; -} - -int is_blkdev(int fd) -{ - struct stat st; - return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)); -} - -off_t -blkdev_find_size (int fd) { - uintmax_t high, low = 0; - - for (high = 1024; blkdev_valid_offset (fd, high); ) { - if (high == UINTMAX_MAX) - return -1; - - low = high; - - if (high >= UINTMAX_MAX/2) - high = UINTMAX_MAX; - else - high *= 2; - } - - while (low < high - 1) - { - uintmax_t mid = (low + high) / 2; - - if (blkdev_valid_offset (fd, mid)) - low = mid; - else - high = mid; - } - blkdev_valid_offset (fd, 0); - return (low + 1); -} - -/* get size in bytes */ -int -blkdev_get_size(int fd, unsigned long long *bytes) -{ -#ifdef DKIOCGETBLOCKCOUNT - /* Apple Darwin */ - if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) { - *bytes <<= 9; - return 0; - } -#endif - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, bytes) >= 0) - return 0; -#endif - -#ifdef BLKGETSIZE - { - unsigned long size; - - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - *bytes = ((unsigned long long)size << 9); - return 0; - } - } - -#endif /* BLKGETSIZE */ - -#ifdef DIOCGMEDIASIZE - /* FreeBSD */ - if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0) - return 0; -#endif - -#ifdef FDGETPRM - { - struct floppy_struct this_floppy; - - if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { - *bytes = ((unsigned long long) this_floppy.size) << 9; - return 0; - } - } -#endif /* FDGETPRM */ - -#if defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) - { - /* - * This code works for FreeBSD 4.11 i386, except for the full device - * (such as /dev/ad0). It doesn't work properly for newer FreeBSD - * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE - * above however. - * - * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, - * character) devices, so we need to check for S_ISCHR, too. - */ - int part = -1; - struct disklabel lab; - struct partition *pp; - struct stat st; - - if ((fstat(fd, &st) >= 0) && - (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) - part = st.st_rdev & 7; - - if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { - pp = &lab.d_partitions[part]; - if (pp->p_size) { - *bytes = pp->p_size << 9; - return 0; - } - } - } -#endif /* defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) */ - - { - struct stat st; - - if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { - *bytes = st.st_size; - return 0; - } - if (!S_ISBLK(st.st_mode)) - return -1; - } - - *bytes = blkdev_find_size(fd); - return 0; -} - -/* get 512-byte sector count */ -int -blkdev_get_sectors(int fd, unsigned long long *sectors) -{ - unsigned long long bytes; - - if (blkdev_get_size(fd, &bytes) == 0) { - *sectors = (bytes >> 9); - return 0; - } - - return -1; -} - -/* - * Get logical sector size. - * - * This is the smallest unit the storage device can - * address. It is typically 512 bytes. - */ -#ifdef BLKSSZGET -int blkdev_get_sector_size(int fd, int *sector_size) -{ - if (ioctl(fd, BLKSSZGET, sector_size) >= 0) - return 0; - return -1; -} -#else -int blkdev_get_sector_size(int fd __attribute__((__unused__)), int *sector_size) -{ - *sector_size = DEFAULT_SECTOR_SIZE; - return 0; -} -#endif - -/* - * Get physical block device size. The BLKPBSZGET is supported since Linux - * 2.6.32. For old kernels is probably the best to assume that physical sector - * size is the same as logical sector size. - * - * Example: - * - * rc = blkdev_get_physector_size(fd, &physec); - * if (rc || physec == 0) { - * rc = blkdev_get_sector_size(fd, &physec); - * if (rc) - * physec = DEFAULT_SECTOR_SIZE; - * } - */ -#ifdef BLKPBSZGET -int blkdev_get_physector_size(int fd, int *sector_size) -{ - if (ioctl(fd, BLKPBSZGET, §or_size) >= 0) - return 0; - return -1; -} -#else -int blkdev_get_physector_size(int fd __attribute__((__unused__)), int *sector_size) -{ - *sector_size = DEFAULT_SECTOR_SIZE; - return 0; -} -#endif - -/* - * Return the alignment status of a device - */ -#ifdef BLKALIGNOFF -int blkdev_is_misaligned(int fd) -{ - int aligned; - - if (ioctl(fd, BLKALIGNOFF, &aligned) < 0) - return 0; /* probably kernel < 2.6.32 */ - /* - * Note that kernel returns -1 as alignment offset if no compatible - * sizes and alignments exist for stacked devices - */ - return aligned != 0 ? 1 : 0; -} -#else -int blkdev_is_misaligned(int fd __attribute__((__unused__))) -{ - return 0; -} -#endif - -int open_blkdev_or_file(const struct stat *st, const char *name, const int oflag) -{ - int fd; - - if (S_ISBLK(st->st_mode)) { - fd = open(name, oflag | O_EXCL); - } else - fd = open(name, oflag); - if (-1 < fd && !is_same_inode(fd, st)) { - close(fd); - errno = EBADFD; - return -1; - } - if (-1 < fd && S_ISBLK(st->st_mode) && blkdev_is_misaligned(fd)) - warnx(_("warning: %s is misaligned"), name); - return fd; -} - -#ifdef CDROM_GET_CAPABILITY -int blkdev_is_cdrom(int fd) -{ - int ret; - - if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0) - return 0; - - return ret; -} -#else -int blkdev_is_cdrom(int fd __attribute__((__unused__))) -{ - return 0; -} -#endif - -/* - * Get kernel's interpretation of the device's geometry. - * - * Returns the heads and sectors - but not cylinders - * as it's truncated for disks with more than 65535 tracks. - * - * Note that this is deprecated in favor of LBA addressing. - */ -#ifdef HDIO_GETGEO -int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s) -{ - struct hd_geometry geometry; - - if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) { - *h = geometry.heads; - *s = geometry.sectors; - return 0; - } -#else -int blkdev_get_geometry(int fd __attribute__((__unused__)), - unsigned int *h, unsigned int *s) -{ - *h = 0; - *s = 0; -#endif - return -1; -} - -/* - * Convert scsi type to human readable string. - */ -const char *blkdev_scsi_type_to_name(int type) -{ - switch (type) { - case SCSI_TYPE_DISK: - return "disk"; - case SCSI_TYPE_TAPE: - return "tape"; - case SCSI_TYPE_PRINTER: - return "printer"; - case SCSI_TYPE_PROCESSOR: - return "processor"; - case SCSI_TYPE_WORM: - return "worm"; - case SCSI_TYPE_ROM: - return "rom"; - case SCSI_TYPE_SCANNER: - return "scanner"; - case SCSI_TYPE_MOD: - return "mo-disk"; - case SCSI_TYPE_MEDIUM_CHANGER: - return "changer"; - case SCSI_TYPE_COMM: - return "comm"; - case SCSI_TYPE_RAID: - return "raid"; - case SCSI_TYPE_ENCLOSURE: - return "enclosure"; - case SCSI_TYPE_RBC: - return "rbc"; - case SCSI_TYPE_OSD: - return "osd"; - case SCSI_TYPE_NO_LUN: - return "no-lun"; - default: - break; - } - return NULL; -} - -/* return 0 on success */ -int blkdev_lock(int fd, const char *devname, const char *lockmode) -{ - int oper, rc, msg = 0; - - if (!lockmode) - lockmode = getenv("LOCK_BLOCK_DEVICE"); - if (!lockmode) - return 0; - - if (strcasecmp(lockmode, "yes") == 0 || - strcmp(lockmode, "1") == 0) - oper = LOCK_EX; - - else if (strcasecmp(lockmode, "nonblock") == 0) - oper = LOCK_EX | LOCK_NB; - - else if (strcasecmp(lockmode, "no") == 0 || - strcmp(lockmode, "0") == 0) - return 0; - else { - warnx(_("unsupported lock mode: %s"), lockmode); - return -EINVAL; - } - - if (!(oper & LOCK_NB)) { - /* Try non-block first to provide message */ - rc = flock(fd, oper | LOCK_NB); - if (rc == 0) - return 0; - if (rc != 0 && errno == EWOULDBLOCK) { - fprintf(stderr, _("%s: %s: device already locked, waiting to get lock ... "), - program_invocation_short_name, devname); - msg = 1; - } - } - rc = flock(fd, oper); - if (rc != 0) { - switch (errno) { - case EWOULDBLOCK: /* LOCK_NB */ - warnx(_("%s: device already locked"), devname); - break; - default: - warn(_("%s: failed to get lock"), devname); - } - } else if (msg) - fprintf(stderr, _("OK\n")); - return rc; -} - - -#ifdef TEST_PROGRAM_BLKDEV -#include -#include -#include -int -main(int argc, char **argv) -{ - unsigned long long bytes; - unsigned long long sectors; - int sector_size, phy_sector_size; - int fd; - - if (argc != 2) { - fprintf(stderr, "usage: %s device\n", argv[0]); - exit(EXIT_FAILURE); - } - - if ((fd = open(argv[1], O_RDONLY|O_CLOEXEC)) < 0) - err(EXIT_FAILURE, "open %s failed", argv[1]); - - if (blkdev_get_size(fd, &bytes) < 0) - err(EXIT_FAILURE, "blkdev_get_size() failed"); - if (blkdev_get_sectors(fd, §ors) < 0) - err(EXIT_FAILURE, "blkdev_get_sectors() failed"); - if (blkdev_get_sector_size(fd, §or_size) < 0) - err(EXIT_FAILURE, "blkdev_get_sector_size() failed"); - if (blkdev_get_physector_size(fd, &phy_sector_size) < 0) - err(EXIT_FAILURE, "blkdev_get_physector_size() failed"); - - printf(" bytes: %llu\n", bytes); - printf(" sectors: %llu\n", sectors); - printf(" sector size: %d\n", sector_size); - printf("phy-sector size: %d\n", phy_sector_size); - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_BLKDEV */ diff --git a/utils/lib/canonicalize.c b/utils/lib/canonicalize.c deleted file mode 100644 index e101c5b..0000000 --- a/utils/lib/canonicalize.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * canonicalize.c -- canonicalize pathname by removing symlinks - * - * This file may be distributed under the terms of the - * GNU Lesser General Public License. - * - * Copyright (C) 2009-2013 Karel Zak - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "canonicalize.h" -#include "pathnames.h" -#include "all-io.h" - -/* - * Converts private "dm-N" names to "/dev/mapper/" - * - * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs - * provides the real DM device names in /sys/block//dm/name - */ -char *__canonicalize_dm_name(const char *prefix, const char *ptname) -{ - FILE *f; - size_t sz; - char path[256], name[sizeof(path) - sizeof(_PATH_DEV_MAPPER)], *res = NULL; - - if (!ptname || !*ptname) - return NULL; - - if (!prefix) - prefix = ""; - - snprintf(path, sizeof(path), "%s/sys/block/%s/dm/name", prefix, ptname); - if (!(f = fopen(path, "r" UL_CLOEXECSTR))) - return NULL; - - /* read "\n" from sysfs */ - if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { - name[sz - 1] = '\0'; - snprintf(path, sizeof(path), _PATH_DEV_MAPPER "/%s", name); - - if ((prefix && *prefix) || access(path, F_OK) == 0) - res = strdup(path); - } - fclose(f); - return res; -} - -char *canonicalize_dm_name(const char *ptname) -{ - return __canonicalize_dm_name(NULL, ptname); -} - -static int is_dm_devname(char *canonical, char **name) -{ - struct stat sb; - char *p = strrchr(canonical, '/'); - - *name = NULL; - - if (!p - || strncmp(p, "/dm-", 4) != 0 - || !isdigit(*(p + 4)) - || stat(canonical, &sb) != 0 - || !S_ISBLK(sb.st_mode)) - return 0; - - *name = p + 1; - return 1; -} - -/* - * This function does not canonicalize the path! It just prepends CWD before a - * relative path. If the path is no relative than returns NULL. The path does - * not have to exist. - */ -char *absolute_path(const char *path) -{ - char cwd[PATH_MAX], *res, *p; - size_t psz, csz; - - if (!is_relative_path(path)) { - errno = EINVAL; - return NULL; - } - if (!getcwd(cwd, sizeof(cwd))) - return NULL; - - /* simple clean up */ - if (startswith(path, "./")) - path += 2; - else if (strcmp(path, ".") == 0) - path = NULL; - - if (!path || !*path) - return strdup(cwd); - - csz = strlen(cwd); - psz = strlen(path); - - p = res = malloc(csz + 1 + psz + 1); - if (!res) - return NULL; - - memcpy(p, cwd, csz); - p += csz; - *p++ = '/'; - memcpy(p, path, psz + 1); - - return res; -} - -char *canonicalize_path(const char *path) -{ - char *canonical, *dmname; - - if (!path || !*path) - return NULL; - - canonical = realpath(path, NULL); - if (!canonical) - return strdup(path); - - if (is_dm_devname(canonical, &dmname)) { - char *dm = canonicalize_dm_name(dmname); - if (dm) { - free(canonical); - return dm; - } - } - - return canonical; -} - -char *canonicalize_path_restricted(const char *path) -{ - char *canonical = NULL; - int errsv = 0; - int pipes[2]; - ssize_t len; - pid_t pid; - - if (!path || !*path) - return NULL; - - if (pipe(pipes) != 0) - return NULL; - - /* - * To accurately assume identity of getuid() we must use setuid() - * but if we do that, we lose ability to reassume euid of 0, so - * we fork to do the check to keep euid intact. - */ - pid = fork(); - switch (pid) { - case -1: - close(pipes[0]); - close(pipes[1]); - return NULL; /* fork error */ - case 0: - close(pipes[0]); /* close unused end */ - pipes[0] = -1; - errno = 0; - - /* drop permissions */ - if (setgid(getgid()) < 0 || setuid(getuid()) < 0) - canonical = NULL; /* failed */ - else { - char *dmname = NULL; - - canonical = realpath(path, NULL); - if (canonical && is_dm_devname(canonical, &dmname)) { - char *dm = canonicalize_dm_name(dmname); - if (dm) { - free(canonical); - canonical = dm; - } - } - } - - len = canonical ? (ssize_t) strlen(canonical) : - errno ? -errno : -EINVAL; - - /* send length or errno */ - write_all(pipes[1], (char *) &len, sizeof(len)); - if (canonical) - write_all(pipes[1], canonical, len); - exit(0); - default: - break; - } - - close(pipes[1]); /* close unused end */ - pipes[1] = -1; - - /* read size or -errno */ - if (read_all(pipes[0], (char *) &len, sizeof(len)) != sizeof(len)) - goto done; - if (len < 0) { - errsv = -len; - goto done; - } - - canonical = malloc(len + 1); - if (!canonical) { - errsv = ENOMEM; - goto done; - } - /* read path */ - if (read_all(pipes[0], canonical, len) != len) { - errsv = errno; - goto done; - } - canonical[len] = '\0'; -done: - if (errsv) { - free(canonical); - canonical = NULL; - } - close(pipes[0]); - - /* We make a best effort to reap child */ - waitpid(pid, NULL, 0); - - errno = errsv; - return canonical; -} - - -#ifdef TEST_PROGRAM_CANONICALIZE -int main(int argc, char **argv) -{ - if (argc < 2) { - fprintf(stderr, "usage: %s \n", argv[0]); - exit(EXIT_FAILURE); - } - - fprintf(stdout, "orig: %s\n", argv[1]); - fprintf(stdout, "real: %s\n", canonicalize_path(argv[1])); - exit(EXIT_SUCCESS); -} -#endif diff --git a/utils/lib/caputils.c b/utils/lib/caputils.c deleted file mode 100644 index 17e9c01..0000000 --- a/utils/lib/caputils.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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; either version 2, or (at your option) any - * later version. - * - * This program 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. - * - * 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 "caputils.h" -#include "pathnames.h" - -int cap_last_cap(void) -{ - /* CAP_LAST_CAP is untrustworthy. */ - static int ret = -1; - int matched; - FILE *f; - - if (ret != -1) - return ret; - - f = fopen(_PATH_PROC_CAPLASTCAP, "r"); - if (!f) { - ret = CAP_LAST_CAP; /* guess */ - return ret; - } - - matched = fscanf(f, "%d", &ret); - fclose(f); - - if (matched != 1) - ret = CAP_LAST_CAP; /* guess */ - - return ret; -} diff --git a/utils/lib/color-names.c b/utils/lib/color-names.c deleted file mode 100644 index 9b1505e..0000000 --- a/utils/lib/color-names.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak - */ -#include "c.h" -#include "color-names.h" - -struct ul_color_name { - const char *name; - const char *seq; -}; - -/* - * qsort/bsearch buddy - */ -static int cmp_color_name(const void *a0, const void *b0) -{ - const struct ul_color_name - *a = (const struct ul_color_name *) a0, - *b = (const struct ul_color_name *) b0; - return strcmp(a->name, b->name); -} - -/* - * Maintains human readable color names - */ -const char *color_sequence_from_colorname(const char *str) -{ - static const struct ul_color_name basic_schemes[] = { - { "black", UL_COLOR_BLACK }, - { "blink", UL_COLOR_BLINK }, - { "blue", UL_COLOR_BLUE }, - { "bold", UL_COLOR_BOLD }, - { "brown", UL_COLOR_BROWN }, - { "cyan", UL_COLOR_CYAN }, - { "darkgray", UL_COLOR_DARK_GRAY }, - { "gray", UL_COLOR_GRAY }, - { "green", UL_COLOR_GREEN }, - { "halfbright", UL_COLOR_HALFBRIGHT }, - { "lightblue", UL_COLOR_BOLD_BLUE }, - { "lightcyan", UL_COLOR_BOLD_CYAN }, - { "lightgray,", UL_COLOR_GRAY }, - { "lightgreen", UL_COLOR_BOLD_GREEN }, - { "lightmagenta", UL_COLOR_BOLD_MAGENTA }, - { "lightred", UL_COLOR_BOLD_RED }, - { "magenta", UL_COLOR_MAGENTA }, - { "red", UL_COLOR_RED }, - { "reset", UL_COLOR_RESET, }, - { "reverse", UL_COLOR_REVERSE }, - { "yellow", UL_COLOR_BOLD_YELLOW }, - { "white", UL_COLOR_WHITE } - }; - struct ul_color_name key = { .name = str }, *res; - - if (!str) - return NULL; - - res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes), - sizeof(struct ul_color_name), - cmp_color_name); - return res ? res->seq : NULL; -} diff --git a/utils/lib/colors.c b/utils/lib/colors.c deleted file mode 100644 index e317519..0000000 --- a/utils/lib/colors.c +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Copyright (C) 2012 Ondrej Oprala - * Copyright (C) 2012-2014 Karel Zak - * - * This file may be distributed under the terms of the - * GNU Lesser General Public License. - */ -#include -#include -#include -#include -#include - -#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW) -# if defined(HAVE_NCURSESW_NCURSES_H) -# include -# elif defined(HAVE_NCURSES_NCURSES_H) -# include -# elif defined(HAVE_NCURSES_H) -# include -# endif -# if defined(HAVE_NCURSESW_TERM_H) -# include -# elif defined(HAVE_NCURSES_TERM_H) -# include -# elif defined(HAVE_TERM_H) -# include -# endif -#endif - -#include "c.h" -#include "colors.h" -#include "pathnames.h" -#include "strutils.h" - -#include "debug.h" - -/* - * Default behavior, may be overridden by terminal-colors.d/{enable,disable}. - */ -#ifdef USE_COLORS_BY_DEFAULT -# define UL_COLORMODE_DEFAULT UL_COLORMODE_AUTO /* check isatty() */ -#else -# define UL_COLORMODE_DEFAULT UL_COLORMODE_NEVER /* no colors by default */ -#endif - -/* - * terminal-colors.d debug stuff - */ -static UL_DEBUG_DEFINE_MASK(termcolors); -UL_DEBUG_DEFINE_MASKNAMES(termcolors) = UL_DEBUG_EMPTY_MASKNAMES; - -#define TERMCOLORS_DEBUG_INIT (1 << 1) -#define TERMCOLORS_DEBUG_CONF (1 << 2) -#define TERMCOLORS_DEBUG_SCHEME (1 << 3) -#define TERMCOLORS_DEBUG_ALL 0xFFFF - -#define DBG(m, x) __UL_DBG(termcolors, TERMCOLORS_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(termcolors, TERMCOLORS_DEBUG_, m, x) - -/* - * terminal-colors.d file types - */ -enum { - UL_COLORFILE_DISABLE, /* .disable */ - UL_COLORFILE_ENABLE, /* .enable */ - UL_COLORFILE_SCHEME, /* .scheme */ - - __UL_COLORFILE_COUNT -}; - -struct ul_color_scheme { - char *name; - char *seq; -}; - -/* - * Global colors control struct - * - * The terminal-colors.d/ evaluation is based on "scores": - * - * filename score - * --------------------------------------- - * type 1 - * @termname.type 10 + 1 - * utilname.type 20 + 1 - * utilname@termname.type 20 + 10 + 1 - * - * the match with higher score wins. The score is per type. - */ -struct ul_color_ctl { - const char *utilname; /* util name */ - const char *termname; /* terminal name ($TERM) */ - - char *sfile; /* path to scheme */ - - struct ul_color_scheme *schemes; /* array with color schemes */ - size_t nschemes; /* number of the items */ - size_t schemes_sz; /* number of the allocated items */ - - int mode; /* UL_COLORMODE_* */ - unsigned int has_colors : 1, /* based on mode and scores[] */ - disabled : 1, /* disable colors */ - cs_configured : 1, /* color schemes read */ - configured : 1; /* terminal-colors.d parsed */ - - int scores[__UL_COLORFILE_COUNT]; /* the best match */ -}; - -/* - * Control struct, globally shared. - */ -static struct ul_color_ctl ul_colors; - -static void colors_free_schemes(struct ul_color_ctl *cc); -static int colors_read_schemes(struct ul_color_ctl *cc); - -/* - * qsort/bsearch buddy - */ -static int cmp_scheme_name(const void *a0, const void *b0) -{ - const struct ul_color_scheme *a = (const struct ul_color_scheme *) a0, - *b = (const struct ul_color_scheme *) b0; - return strcmp(a->name, b->name); -} - -/* - * Resets control struct (note that we don't allocate the struct) - */ -static void colors_reset(struct ul_color_ctl *cc) -{ - if (!cc) - return; - - colors_free_schemes(cc); - - free(cc->sfile); - - cc->sfile = NULL; - cc->utilname = NULL; - cc->termname = NULL; - cc->mode = UL_COLORMODE_UNDEF; - - memset(cc->scores, 0, sizeof(cc->scores)); -} - -static void colors_debug(struct ul_color_ctl *cc) -{ - size_t i; - - if (!cc) - return; - - printf("Colors:\n"); - printf("\tutilname = '%s'\n", cc->utilname); - printf("\ttermname = '%s'\n", cc->termname); - printf("\tscheme file = '%s'\n", cc->sfile); - printf("\tmode = %s\n", - cc->mode == UL_COLORMODE_UNDEF ? "undefined" : - cc->mode == UL_COLORMODE_AUTO ? "auto" : - cc->mode == UL_COLORMODE_NEVER ? "never" : - cc->mode == UL_COLORMODE_ALWAYS ? "always" : "???"); - printf("\thas_colors = %d\n", cc->has_colors); - printf("\tdisabled = %d\n", cc->disabled); - printf("\tconfigured = %d\n", cc->configured); - printf("\tcs configured = %d\n", cc->cs_configured); - - fputc('\n', stdout); - - for (i = 0; i < ARRAY_SIZE(cc->scores); i++) - printf("\tscore %s = %d\n", - i == UL_COLORFILE_DISABLE ? "disable" : - i == UL_COLORFILE_ENABLE ? "enable" : - i == UL_COLORFILE_SCHEME ? "scheme" : "???", - cc->scores[i]); - - fputc('\n', stdout); - - for (i = 0; i < cc->nschemes; i++) { - printf("\tscheme #%02zu ", i); - color_scheme_enable(cc->schemes[i].name, NULL); - fputs(cc->schemes[i].name, stdout); - color_disable(); - fputc('\n', stdout); - } - fputc('\n', stdout); -} - -/* - * Parses [[][@].] - */ -static int filename_to_tokens(const char *str, - const char **name, size_t *namesz, - const char **term, size_t *termsz, - int *filetype) -{ - const char *type_start, *term_start, *p; - - if (!str || !*str || *str == '.' || strlen(str) > PATH_MAX) - return -EINVAL; - - /* parse .type */ - p = strrchr(str, '.'); - type_start = p ? p + 1 : str; - - if (strcmp(type_start, "disable") == 0) - *filetype = UL_COLORFILE_DISABLE; - else if (strcmp(type_start, "enable") == 0) - *filetype = UL_COLORFILE_ENABLE; - else if (strcmp(type_start, "scheme") == 0) - *filetype = UL_COLORFILE_SCHEME; - else { - DBG(CONF, ul_debug("unknown type '%s'", type_start)); - return 1; /* unknown type */ - } - - if (type_start == str) - return 0; /* "type" only */ - - /* parse @termname */ - p = strchr(str, '@'); - term_start = p ? p + 1 : NULL; - if (term_start) { - *term = term_start; - *termsz = type_start - term_start - 1; - if (term_start - 1 == str) - return 0; /* "@termname.type" */ - } - - /* parse utilname */ - p = term_start ? term_start : type_start; - *name = str; - *namesz = p - str - 1; - - return 0; -} - -/* - * Scans @dirname and select the best matches for UL_COLORFILE_* types. - * The result is stored to cc->scores. The path to the best "scheme" - * file is stored to cc->scheme. - */ -static int colors_readdir(struct ul_color_ctl *cc, const char *dirname) -{ - DIR *dir; - int rc = 0; - struct dirent *d; - char sfile[PATH_MAX] = { '\0' }; - size_t namesz, termsz; - - if (!dirname || !cc || !cc->utilname || !*cc->utilname) - return -EINVAL; - - DBG(CONF, ul_debug("reading dir: '%s'", dirname)); - - dir = opendir(dirname); - if (!dir) - return -errno; - - namesz = strlen(cc->utilname); - termsz = cc->termname ? strlen(cc->termname) : 0; - - while ((d = readdir(dir))) { - int type, score = 1; - const char *tk_name = NULL, *tk_term = NULL; - size_t tk_namesz = 0, tk_termsz = 0; - - if (*d->d_name == '.') - continue; -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK && - d->d_type != DT_REG) - continue; -#endif - if (filename_to_tokens(d->d_name, - &tk_name, &tk_namesz, - &tk_term, &tk_termsz, &type) != 0) - continue; - - /* count theoretical score before we check names to avoid - * unnecessary strcmp() */ - if (tk_name) - score += 20; - if (tk_term) - score += 10; - - DBG(CONF, ul_debug("item '%s': score=%d " - "[cur: %d, name(%zu): %s, term(%zu): %s]", - d->d_name, score, cc->scores[type], - tk_namesz, tk_name, - tk_termsz, tk_term)); - - - if (score < cc->scores[type]) - continue; - - /* filter out by names */ - if (tk_namesz && (tk_namesz != namesz || - strncmp(tk_name, cc->utilname, namesz) != 0)) - continue; - - if (tk_termsz && (termsz == 0 || tk_termsz != termsz || - strncmp(tk_term, cc->termname, termsz) != 0)) - continue; - - DBG(CONF, ul_debug("setting '%s' from %d -to-> %d", - type == UL_COLORFILE_SCHEME ? "scheme" : - type == UL_COLORFILE_DISABLE ? "disable" : - type == UL_COLORFILE_ENABLE ? "enable" : "???", - cc->scores[type], score)); - cc->scores[type] = score; - if (type == UL_COLORFILE_SCHEME) - strncpy(sfile, d->d_name, sizeof(sfile)); - } - - if (*sfile) { - sfile[sizeof(sfile) - 1] = '\0'; - if (asprintf(&cc->sfile, "%s/%s", dirname, sfile) <= 0) - rc = -ENOMEM; - } - - closedir(dir); - return rc; -} - -/* atexit() wrapper */ -static void colors_deinit(void) -{ - colors_reset(&ul_colors); -} - -/* - * Returns path to $XDG_CONFIG_HOME/terminal-colors.d - */ -static char *colors_get_homedir(char *buf, size_t bufsz) -{ - char *p = getenv("XDG_CONFIG_HOME"); - - if (p) { - snprintf(buf, bufsz, "%s/" _PATH_TERMCOLORS_DIRNAME, p); - return buf; - } - - p = getenv("HOME"); - if (p) { - snprintf(buf, bufsz, "%s/.config/" _PATH_TERMCOLORS_DIRNAME, p); - return buf; - } - - return NULL; -} - -/* canonicalize sequence */ -static int cn_sequence(const char *str, char **seq) -{ - char *in, *out; - int len; - - if (!str) - return -EINVAL; - - *seq = NULL; - - /* convert logical names like "red" to the real sequence */ - if (*str != '\\' && isalpha(*str)) { - const char *s = color_sequence_from_colorname(str); - *seq = strdup(s ? s : str); - - return *seq ? 0 : -ENOMEM; - } - - /* convert xx;yy sequences to "\033[xx;yy" */ - if ((len = asprintf(seq, "\033[%sm", str)) < 1) - return -ENOMEM; - - for (in = *seq, out = *seq; in && *in; in++) { - if (*in != '\\') { - *out++ = *in; - continue; - } - switch(*(in + 1)) { - case 'a': - *out++ = '\a'; /* Bell */ - break; - case 'b': - *out++ = '\b'; /* Backspace */ - break; - case 'e': - *out++ = '\033'; /* Escape */ - break; - case 'f': - *out++ = '\f'; /* Form Feed */ - break; - case 'n': - *out++ = '\n'; /* Newline */ - break; - case 'r': - *out++ = '\r'; /* Carriage Return */ - break; - case 't': - *out++ = '\t'; /* Tab */ - break; - case 'v': - *out++ = '\v'; /* Vertical Tab */ - break; - case '\\': - *out++ = '\\'; /* Backslash */ - break; - case '_': - *out++ = ' '; /* Space */ - break; - case '#': - *out++ = '#'; /* Hash mark */ - break; - case '?': - *out++ = '?'; /* Question mark */ - break; - default: - *out++ = *in; - *out++ = *(in + 1); - break; - } - in++; - } - - if (out) { - assert ((out - *seq) <= len); - *out = '\0'; - } - - return 0; -} - - -/* - * Adds one color sequence to array with color scheme. - * When returning success (0) this function takes ownership of - * @seq and @name, which have to be allocated strings. - */ -static int colors_add_scheme(struct ul_color_ctl *cc, - char *name, - char *seq0) -{ - struct ul_color_scheme *cs = NULL; - char *seq = NULL; - int rc; - - if (!cc || !name || !*name || !seq0 || !*seq0) - return -EINVAL; - - DBG(SCHEME, ul_debug("add '%s'", name)); - - rc = cn_sequence(seq0, &seq); - if (rc) - return rc; - - rc = -ENOMEM; - - /* convert logical name (e.g. "red") to real ESC code */ - if (isalpha(*seq)) { - const char *s = color_sequence_from_colorname(seq); - char *p; - - if (!s) { - DBG(SCHEME, ul_debug("unknown logical name: %s", seq)); - rc = -EINVAL; - goto err; - } - - p = strdup(s); - if (!p) - goto err; - free(seq); - seq = p; - } - - /* enlarge the array */ - if (cc->nschemes == cc->schemes_sz) { - void *tmp = realloc(cc->schemes, (cc->nschemes + 10) - * sizeof(struct ul_color_scheme)); - if (!tmp) - goto err; - cc->schemes = tmp; - cc->schemes_sz = cc->nschemes + 10; - } - - /* add a new item */ - cs = &cc->schemes[cc->nschemes]; - cs->seq = seq; - cs->name = strdup(name); - if (!cs->name) - goto err; - - cc->nschemes++; - return 0; -err: - if (cs) { - free(cs->seq); - free(cs->name); - cs->seq = cs->name = NULL; - } else - free(seq); - return rc; -} - -/* - * Deallocates all regards to color schemes - */ -static void colors_free_schemes(struct ul_color_ctl *cc) -{ - size_t i; - - DBG(SCHEME, ul_debug("free scheme")); - - for (i = 0; i < cc->nschemes; i++) { - free(cc->schemes[i].name); - free(cc->schemes[i].seq); - } - - free(cc->schemes); - cc->schemes = NULL; - cc->nschemes = 0; - cc->schemes_sz = 0; -} - -/* - * The scheme configuration has to be sorted for bsearch - */ -static void colors_sort_schemes(struct ul_color_ctl *cc) -{ - if (!cc->nschemes) - return; - - DBG(SCHEME, ul_debug("sort scheme")); - - qsort(cc->schemes, cc->nschemes, - sizeof(struct ul_color_scheme), cmp_scheme_name); -} - -/* - * Returns just one color scheme - */ -static struct ul_color_scheme *colors_get_scheme(struct ul_color_ctl *cc, - const char *name) -{ - struct ul_color_scheme key = { .name = (char *) name}, *res; - - if (!cc || !name || !*name) - return NULL; - - if (!cc->cs_configured) { - int rc = colors_read_schemes(cc); - if (rc) - return NULL; - } - if (!cc->nschemes) - return NULL; - - DBG(SCHEME, ul_debug("search '%s'", name)); - - res = bsearch(&key, cc->schemes, cc->nschemes, - sizeof(struct ul_color_scheme), - cmp_scheme_name); - - return res && res->seq ? res : NULL; -} - -/* - * Parses filenames in terminal-colors.d - */ -static int colors_read_configuration(struct ul_color_ctl *cc) -{ - int rc = -ENOENT; - char *dirname, buf[PATH_MAX]; - - cc->termname = getenv("TERM"); - - dirname = colors_get_homedir(buf, sizeof(buf)); - if (dirname) - rc = colors_readdir(cc, dirname); /* ~/.config */ - if (rc == -EPERM || rc == -EACCES || rc == -ENOENT) - rc = colors_readdir(cc, _PATH_TERMCOLORS_DIR); /* /etc */ - - cc->configured = 1; - return rc; -} - -/* - * Reads terminal-colors.d/ scheme file into array schemes - */ -static int colors_read_schemes(struct ul_color_ctl *cc) -{ - int rc = 0; - FILE *f = NULL; - char buf[BUFSIZ], - cn[129], seq[129]; - - if (!cc->configured) - rc = colors_read_configuration(cc); - - cc->cs_configured = 1; - - if (rc || !cc->sfile) - goto done; - - DBG(SCHEME, ul_debug("reading file '%s'", cc->sfile)); - - f = fopen(cc->sfile, "r"); - if (!f) { - rc = -errno; - goto done; - } - - while (fgets(buf, sizeof(buf), f)) { - char *p = strchr(buf, '\n'); - - if (!p) { - if (feof(f)) - p = strchr(buf, '\0'); - else { - rc = -errno; - goto done; - } - } - *p = '\0'; - p = (char *) skip_blank(buf); - if (*p == '\0' || *p == '#') - continue; - - rc = sscanf(p, "%128[^ ] %128[^\n ]", cn, seq); - if (rc == 2 && *cn && *seq) { - rc = colors_add_scheme(cc, cn, seq); /* set rc=0 on success */ - if (rc) - goto done; - } - } - rc = 0; - -done: - if (f) - fclose(f); - colors_sort_schemes(cc); - - return rc; -} - - -static void termcolors_init_debug(void) -{ - __UL_INIT_DEBUG_FROM_ENV(termcolors, TERMCOLORS_DEBUG_, 0, TERMINAL_COLORS_DEBUG); -} - -static int colors_terminal_is_ready(void) -{ - int ncolors = -1; - -#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW) - { - int ret; - - if (setupterm(NULL, STDOUT_FILENO, &ret) == 0 && ret == 1) - ncolors = tigetnum("colors"); - } -#endif - if (1 < ncolors) { - DBG(CONF, ul_debug("terminal is ready (supports %d colors)", ncolors)); - return 1; - } - - DBG(CONF, ul_debug("terminal is NOT ready (no colors)")); - return 0; -} - -/** - * colors_init: - * @mode: UL_COLORMODE_* - * @name: util argv[0] - * - * Initialize private color control struct and initialize the colors - * status. The color schemes are parsed on demand by colors_get_scheme(). - * - * Returns: >0 on success. - */ -int colors_init(int mode, const char *name) -{ - int ready = -1; - struct ul_color_ctl *cc = &ul_colors; - - cc->utilname = name; - - termcolors_init_debug(); - - if (mode != UL_COLORMODE_ALWAYS && !isatty(STDOUT_FILENO)) - cc->mode = UL_COLORMODE_NEVER; - else - cc->mode = mode; - - if (cc->mode == UL_COLORMODE_UNDEF - && (ready = colors_terminal_is_ready())) { - int rc = colors_read_configuration(cc); - if (rc) - cc->mode = UL_COLORMODE_DEFAULT; - else { - - /* evaluate scores */ - if (cc->scores[UL_COLORFILE_DISABLE] > - cc->scores[UL_COLORFILE_ENABLE]) - cc->mode = UL_COLORMODE_NEVER; - else - cc->mode = UL_COLORMODE_DEFAULT; - - atexit(colors_deinit); - } - } - - switch (cc->mode) { - case UL_COLORMODE_AUTO: - cc->has_colors = ready == -1 ? colors_terminal_is_ready() : ready; - break; - case UL_COLORMODE_ALWAYS: - cc->has_colors = 1; - break; - case UL_COLORMODE_NEVER: - default: - cc->has_colors = 0; - } - - ON_DBG(CONF, colors_debug(cc)); - - return cc->has_colors; -} - -/* - * Temporary disable colors (this setting is independent on terminal-colors.d/) - */ -void colors_off(void) -{ - ul_colors.disabled = 1; -} - -/* - * Enable colors - */ -void colors_on(void) -{ - ul_colors.disabled = 0; -} - -/* - * Is terminal-colors.d/ configured to use colors? - */ -int colors_wanted(void) -{ - return ul_colors.has_colors; -} - -/* - * Returns mode - */ -int colors_mode(void) -{ - return ul_colors.mode; -} - -/* - * Enable @seq color - */ -void color_fenable(const char *seq, FILE *f) -{ - if (!ul_colors.disabled && ul_colors.has_colors && seq) - fputs(seq, f); -} - -/* - * Returns escape sequence by logical @name, if undefined then returns @dflt. - */ -const char *color_scheme_get_sequence(const char *name, const char *dflt) -{ - struct ul_color_scheme *cs; - - if (ul_colors.disabled || !ul_colors.has_colors) - return NULL; - - cs = colors_get_scheme(&ul_colors, name); - return cs && cs->seq ? cs->seq : dflt; -} - -/* - * Enable color by logical @name, if undefined enable @dflt. - */ -void color_scheme_fenable(const char *name, const char *dflt, FILE *f) -{ - const char *seq = color_scheme_get_sequence(name, dflt); - - if (!seq) - return; - color_fenable(seq, f); -} - - -/* - * Disable previously enabled color - */ -void color_fdisable(FILE *f) -{ - if (!ul_colors.disabled && ul_colors.has_colors) - fputs(UL_COLOR_RESET, f); -} - -/* - * Parses @str to return UL_COLORMODE_* - */ -int colormode_from_string(const char *str) -{ - size_t i; - static const char *modes[] = { - [UL_COLORMODE_AUTO] = "auto", - [UL_COLORMODE_NEVER] = "never", - [UL_COLORMODE_ALWAYS] = "always", - [UL_COLORMODE_UNDEF] = "" - }; - - if (!str || !*str) - return -EINVAL; - - assert(ARRAY_SIZE(modes) == __UL_NCOLORMODES); - - for (i = 0; i < ARRAY_SIZE(modes); i++) { - if (strcasecmp(str, modes[i]) == 0) - return i; - } - - return -EINVAL; -} - -/* - * Parses @str and exit(EXIT_FAILURE) on error - */ -int colormode_or_err(const char *str, const char *errmsg) -{ - const char *p = str && *str == '=' ? str + 1 : str; - int colormode; - - colormode = colormode_from_string(p); - if (colormode < 0) - errx(EXIT_FAILURE, "%s: '%s'", errmsg, p); - - return colormode; -} - -#ifdef TEST_PROGRAM_COLORS -# include -int main(int argc, char *argv[]) -{ - static const struct option longopts[] = { - { "mode", required_argument, NULL, 'm' }, - { "color", required_argument, NULL, 'c' }, - { "color-scheme", required_argument, NULL, 'C' }, - { "name", required_argument, NULL, 'n' }, - { NULL, 0, NULL, 0 } - }; - int c, mode = UL_COLORMODE_UNDEF; /* default */ - const char *color = "red", *name = NULL, *color_scheme = NULL; - const char *seq = NULL; - - while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) { - switch (c) { - case 'c': - color = optarg; - break; - case 'C': - color_scheme = optarg; - break; - case 'm': - mode = colormode_or_err(optarg, "unsupported color mode"); - break; - case 'n': - name = optarg; - break; - default: - fprintf(stderr, "usage: %s [options]\n" - " -m, --mode default is undefined\n" - " -c, --color color for the test message\n" - " -C, --color-scheme color for the test message\n" - " -n, --name util name\n", - program_invocation_short_name); - return EXIT_FAILURE; - } - } - - colors_init(mode, name ? name : program_invocation_short_name); - - seq = color_sequence_from_colorname(color); - - if (color_scheme) - color_scheme_enable(color_scheme, seq); - else - color_enable(seq); - printf("Hello World!"); - color_disable(); - fputc('\n', stdout); - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_COLORS */ - diff --git a/utils/lib/cpuset.c b/utils/lib/cpuset.c deleted file mode 100644 index 2847db8..0000000 --- a/utils/lib/cpuset.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Terminology: - * - * cpuset - (libc) cpu_set_t data structure represents set of CPUs - * cpumask - string with hex mask (e.g. "0x00000001") - * cpulist - string with CPU ranges (e.g. "0-3,5,7,8") - * - * Based on code from taskset.c and Linux kernel. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * Copyright (C) 2010 Karel Zak - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpuset.h" -#include "c.h" - -static inline int val_to_char(int v) -{ - if (v >= 0 && v < 10) - return '0' + v; - if (v >= 10 && v < 16) - return ('a' - 10) + v; - return -1; -} - -static inline int char_to_val(int c) -{ - int cl; - - if (c >= '0' && c <= '9') - return c - '0'; - cl = tolower(c); - if (cl >= 'a' && cl <= 'f') - return cl + (10 - 'a'); - return -1; -} - -static const char *nexttoken(const char *q, int sep) -{ - if (q) - q = strchr(q, sep); - if (q) - q++; - return q; -} - -/* - * Number of bits in a CPU bitmask on current system - */ -int get_max_number_of_cpus(void) -{ -#ifdef SYS_sched_getaffinity - int n, cpus = 2048; - size_t setsize; - cpu_set_t *set = cpuset_alloc(cpus, &setsize, NULL); - - if (!set) - return -1; /* error */ - - for (;;) { - CPU_ZERO_S(setsize, set); - - /* the library version does not return size of cpumask_t */ - n = syscall(SYS_sched_getaffinity, 0, setsize, set); - - if (n < 0 && errno == EINVAL && cpus < 1024 * 1024) { - cpuset_free(set); - cpus *= 2; - set = cpuset_alloc(cpus, &setsize, NULL); - if (!set) - return -1; /* error */ - continue; - } - cpuset_free(set); - return n * 8; - } -#endif - return -1; -} - -/* - * Allocates a new set for ncpus and returns size in bytes and size in bits - */ -cpu_set_t *cpuset_alloc(int ncpus, size_t *setsize, size_t *nbits) -{ - cpu_set_t *set = CPU_ALLOC(ncpus); - - if (!set) - return NULL; - if (setsize) - *setsize = CPU_ALLOC_SIZE(ncpus); - if (nbits) - *nbits = cpuset_nbits(CPU_ALLOC_SIZE(ncpus)); - return set; -} - -void cpuset_free(cpu_set_t *set) -{ - CPU_FREE(set); -} - -#if !HAVE_DECL_CPU_ALLOC -/* Please, use CPU_COUNT_S() macro. This is fallback */ -int __cpuset_count_s(size_t setsize, const cpu_set_t *set) -{ - int s = 0; - const __cpu_mask *p = set->__bits; - const __cpu_mask *end = &set->__bits[setsize / sizeof (__cpu_mask)]; - - while (p < end) { - __cpu_mask l = *p++; - - if (l == 0) - continue; -# if LONG_BIT > 32 - l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); - l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); - l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); - l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); - l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); - l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); -# else - l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); - l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); - l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); - l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); - l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); -# endif - s += l; - } - return s; -} -#endif - -/* - * Returns human readable representation of the cpuset. The output format is - * a list of CPUs with ranges (for example, "0,1,3-9"). - */ -char *cpulist_create(char *str, size_t len, - cpu_set_t *set, size_t setsize) -{ - size_t i; - char *ptr = str; - int entry_made = 0; - size_t max = cpuset_nbits(setsize); - - for (i = 0; i < max; i++) { - if (CPU_ISSET_S(i, setsize, set)) { - int rlen; - size_t j, run = 0; - entry_made = 1; - for (j = i + 1; j < max; j++) { - if (CPU_ISSET_S(j, setsize, set)) - run++; - else - break; - } - if (!run) - rlen = snprintf(ptr, len, "%zu,", i); - else if (run == 1) { - rlen = snprintf(ptr, len, "%zu,%zu,", i, i + 1); - i++; - } else { - rlen = snprintf(ptr, len, "%zu-%zu,", i, i + run); - i += run; - } - if (rlen < 0 || (size_t) rlen >= len) - return NULL; - ptr += rlen; - len -= rlen; - } - } - ptr -= entry_made; - *ptr = '\0'; - - return str; -} - -/* - * Returns string with CPU mask. - */ -char *cpumask_create(char *str, size_t len, - cpu_set_t *set, size_t setsize) -{ - char *ptr = str; - char *ret = NULL; - int cpu; - - for (cpu = cpuset_nbits(setsize) - 4; cpu >= 0; cpu -= 4) { - char val = 0; - - if (len == (size_t) (ptr - str)) - break; - - if (CPU_ISSET_S(cpu, setsize, set)) - val |= 1; - if (CPU_ISSET_S(cpu + 1, setsize, set)) - val |= 2; - if (CPU_ISSET_S(cpu + 2, setsize, set)) - val |= 4; - if (CPU_ISSET_S(cpu + 3, setsize, set)) - val |= 8; - - if (!ret && val) - ret = ptr; - *ptr++ = val_to_char(val); - } - *ptr = '\0'; - return ret ? ret : ptr - 1; -} - -/* - * Parses string with CPUs mask. - */ -int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize) -{ - int len = strlen(str); - const char *ptr = str + len - 1; - int cpu = 0; - - /* skip 0x, it's all hex anyway */ - if (len > 1 && !memcmp(str, "0x", 2L)) - str += 2; - - CPU_ZERO_S(setsize, set); - - while (ptr >= str) { - char val; - - /* cpu masks in /sys uses comma as a separator */ - if (*ptr == ',') - ptr--; - - val = char_to_val(*ptr); - if (val == (char) -1) - return -1; - if (val & 1) - CPU_SET_S(cpu, setsize, set); - if (val & 2) - CPU_SET_S(cpu + 1, setsize, set); - if (val & 4) - CPU_SET_S(cpu + 2, setsize, set); - if (val & 8) - CPU_SET_S(cpu + 3, setsize, set); - ptr--; - cpu += 4; - } - - return 0; -} - -static int nextnumber(const char *str, char **end, unsigned int *result) -{ - errno = 0; - if (str == NULL || *str == '\0' || !isdigit(*str)) - return -EINVAL; - *result = (unsigned int) strtoul(str, end, 10); - if (errno) - return -errno; - if (str == *end) - return -EINVAL; - return 0; -} - -/* - * Parses string with list of CPU ranges. - * Returns 0 on success. - * Returns 1 on error. - * Returns 2 if fail is set and a cpu number passed in the list doesn't fit - * into the cpu_set. If fail is not set cpu numbers that do not fit are - * ignored and 0 is returned instead. - */ -int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail) -{ - size_t max = cpuset_nbits(setsize); - const char *p, *q; - char *end = NULL; - - q = str; - CPU_ZERO_S(setsize, set); - - while (p = q, q = nexttoken(q, ','), p) { - unsigned int a; /* beginning of range */ - unsigned int b; /* end of range */ - unsigned int s; /* stride */ - const char *c1, *c2; - - if (nextnumber(p, &end, &a) != 0) - return 1; - b = a; - s = 1; - p = end; - - c1 = nexttoken(p, '-'); - c2 = nexttoken(p, ','); - - if (c1 != NULL && (c2 == NULL || c1 < c2)) { - if (nextnumber(c1, &end, &b) != 0) - return 1; - - c1 = end && *end ? nexttoken(end, ':') : NULL; - - if (c1 != NULL && (c2 == NULL || c1 < c2)) { - if (nextnumber(c1, &end, &s) != 0) - return 1; - if (s == 0) - return 1; - } - } - - if (!(a <= b)) - return 1; - while (a <= b) { - if (fail && (a >= max)) - return 2; - CPU_SET_S(a, setsize, set); - a += s; - } - } - - if (end && *end) - return 1; - return 0; -} - -#ifdef TEST_PROGRAM_CPUSET - -#include - -int main(int argc, char *argv[]) -{ - cpu_set_t *set; - size_t setsize, buflen, nbits; - char *buf, *mask = NULL, *range = NULL; - int ncpus = 2048, rc, c; - - static const struct option longopts[] = { - { "ncpus", 1, NULL, 'n' }, - { "mask", 1, NULL, 'm' }, - { "range", 1, NULL, 'r' }, - { NULL, 0, NULL, 0 } - }; - - while ((c = getopt_long(argc, argv, "n:m:r:", longopts, NULL)) != -1) { - switch(c) { - case 'n': - ncpus = atoi(optarg); - break; - case 'm': - mask = strdup(optarg); - break; - case 'r': - range = strdup(optarg); - break; - default: - goto usage_err; - } - } - - if (!mask && !range) - goto usage_err; - - set = cpuset_alloc(ncpus, &setsize, &nbits); - if (!set) - err(EXIT_FAILURE, "failed to allocate cpu set"); - - /* - fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n", - ncpus, nbits, setsize); - */ - - buflen = 7 * nbits; - buf = malloc(buflen); - if (!buf) - err(EXIT_FAILURE, "failed to allocate cpu set buffer"); - - if (mask) - rc = cpumask_parse(mask, set, setsize); - else - rc = cpulist_parse(range, set, setsize, 0); - - if (rc) - errx(EXIT_FAILURE, "failed to parse string: %s", mask ? : range); - - printf("%-15s = %15s ", mask ? : range, - cpumask_create(buf, buflen, set, setsize)); - printf("[%s]\n", cpulist_create(buf, buflen, set, setsize)); - - free(buf); - free(mask); - free(range); - cpuset_free(set); - - return EXIT_SUCCESS; - -usage_err: - fprintf(stderr, - "usage: %s [--ncpus ] --mask | --range \n", - program_invocation_short_name); - exit(EXIT_FAILURE); -} -#endif diff --git a/utils/lib/crc32.c b/utils/lib/crc32.c deleted file mode 100644 index 824693d..0000000 --- a/utils/lib/crc32.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - * code or tables extracted from it, as desired without restriction. - * - * First, the polynomial itself and its table of feedback terms. The - * polynomial is - * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 - * - * Note that we take it "backwards" and put the highest-order term in - * the lowest-order bit. The X^32 term is "implied"; the LSB is the - * X^31 term, etc. The X^0 term (usually shown as "+1") results in - * the MSB being 1. - * - * Note that the usual hardware shift register implementation, which - * is what we're using (we're merely optimizing it by doing eight-bit - * chunks at a time) shifts bits into the lowest-order term. In our - * implementation, that means shifting towards the right. Why do we - * do it this way? Because the calculated CRC must be transmitted in - * order from highest-order term to lowest-order term. UARTs transmit - * characters in order from LSB to MSB. By storing the CRC this way, - * we hand it to the UART in the order low-byte to high-byte; the UART - * sends each low-bit to high-bit; and the result is transmission bit - * by bit from highest- to lowest-order term without requiring any bit - * shuffling on our part. Reception works similarly. - * - * The feedback terms table consists of 256, 32-bit entries. Notes - * - * The table can be generated at runtime if desired; code to do so - * is shown later. It might not be obvious, but the feedback - * terms simply represent the results of eight shift/xor opera- - * tions for all combinations of data and CRC register values. - * - * The values must be right-shifted by eight bits by the "updcrc" - * logic; the shift must be unsigned (bring in zeroes). On some - * hardware you could probably optimize the shift in assembler by - * using byte-swap instructions. - * polynomial $edb88320 - * - */ - -#include - -#include "crc32.h" - - -static const uint32_t crc32_tab[] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -static inline uint32_t crc32_add_char(uint32_t crc, unsigned char c) -{ - return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8); -} - -/* - * This a generic crc32() function, it takes seed as an argument, - * and does __not__ xor at the end. Then individual users can do - * whatever they need. - */ -uint32_t ul_crc32(uint32_t seed, const unsigned char *buf, size_t len) -{ - uint32_t crc = seed; - const unsigned char *p = buf; - - while (len) { - crc = crc32_add_char(crc, *p++); - len--; - } - - return crc; -} - -uint32_t ul_crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len, - size_t exclude_off, size_t exclude_len) -{ - uint32_t crc = seed; - const unsigned char *p = buf; - size_t i; - - for (i = 0; i < len; i++) { - unsigned char x = *p++; - - if (i >= exclude_off && i < exclude_off + exclude_len) - x = 0; - - crc = crc32_add_char(crc, x); - } - - return crc; -} - diff --git a/utils/lib/crc32c.c b/utils/lib/crc32c.c deleted file mode 100644 index 49e7543..0000000 --- a/utils/lib/crc32c.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This code is from freebsd/sys/libkern/crc32.c - * - * Simplest table-based crc32c. Performance is not important - * for checking crcs on superblocks - */ - -/*- - * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - * code or tables extracted from it, as desired without restriction. - */ - -#include "crc32c.h" - -static const uint32_t crc32Table[256] = { - 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, - 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, - 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, - 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, - 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, - 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, - 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, - 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, - 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, - 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, - 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, - 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, - 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, - 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, - 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, - 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, - 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, - 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, - 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, - 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, - 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, - 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, - 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, - 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, - 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, - 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, - 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, - 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, - 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, - 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, - 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, - 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, - 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, - 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, - 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, - 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, - 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, - 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, - 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, - 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, - 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, - 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, - 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, - 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, - 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, - 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, - 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, - 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, - 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, - 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, - 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, - 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, - 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, - 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, - 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, - 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, - 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, - 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, - 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, - 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, - 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, - 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, - 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, - 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L -}; - -/* - *This was singletable_crc32c() in bsd - * - * If you will not be passing crc back into this function to process more bytes, - * the answer is: - * - * crc = crc32c(~0L, buf, size); - * [ crc = crc32c(crc, buf, size); ] - * crc ^= ~0L - * - */ -uint32_t -crc32c(uint32_t crc, const void *buf, size_t size) -{ - const uint8_t *p = buf; - - while (size--) - crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - - return crc; -} diff --git a/utils/lib/encode.c b/utils/lib/encode.c deleted file mode 100644 index 10b5971..0000000 --- a/utils/lib/encode.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Based on code from libblkid, - * - * Copyright (C) 2008 Kay Sievers - * Copyright (C) 2009 Karel Zak - * Copyright (C) 2020 Pali Rohár - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include "c.h" -#include "encode.h" - -size_t ul_encode_to_utf8(int enc, unsigned char *dest, size_t len, - const unsigned char *src, size_t count) -{ - size_t i, j; - uint32_t c; - uint16_t c2; - - for (j = i = 0; i < count; i++) { - if (enc == UL_ENCODE_UTF16LE) { - if (i+2 > count) - break; - c = (src[i+1] << 8) | src[i]; - i++; - } else if (enc == UL_ENCODE_UTF16BE) { - if (i+2 > count) - break; - c = (src[i] << 8) | src[i+1]; - i++; - } else if (enc == UL_ENCODE_LATIN1) { - c = src[i]; - } else { - return 0; - } - if ((enc == UL_ENCODE_UTF16LE || enc == UL_ENCODE_UTF16BE) && - c >= 0xD800 && c <= 0xDBFF && i+2 < count) { - if (enc == UL_ENCODE_UTF16LE) - c2 = (src[i+2] << 8) | src[i+1]; - else - c2 = (src[i+1] << 8) | src[i+2]; - if (c2 >= 0xDC00 && c2 <= 0xDFFF) { - c = 0x10000 + ((c - 0xD800) << 10) + (c2 - 0xDC00); - i += 2; - } - } - if (c == 0) { - dest[j] = '\0'; - break; - } - - if (c < 0x80) { - if (j+1 >= len) - break; - dest[j++] = (uint8_t) c; - } else if (c < 0x800) { - if (j+2 >= len) - break; - dest[j++] = (uint8_t) (0xc0 | (c >> 6)); - dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); - } else if (c < 0x10000) { - if (j+3 >= len) - break; - dest[j++] = (uint8_t) (0xe0 | (c >> 12)); - dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); - dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); - } else { - if (j+4 >= len) - break; - dest[j++] = (uint8_t) (0xf0 | (c >> 18)); - dest[j++] = (uint8_t) (0x80 | ((c >> 12) & 0x3f)); - dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); - dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); - } - } - dest[j] = '\0'; - return j; -} diff --git a/utils/lib/env.c b/utils/lib/env.c deleted file mode 100644 index c26a5be..0000000 --- a/utils/lib/env.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Security checks of environment - * Added from shadow-utils package - * by Arkadiusz MiÅ›kiewicz - * - */ - -#include -#include -#include -#ifdef HAVE_SYS_PRCTL_H -#include -#else -#define PR_GET_DUMPABLE 3 -#endif -#if (!defined(HAVE_PRCTL) && defined(linux)) -#include -#endif -#include -#include - -#include "env.h" - -#ifndef HAVE_ENVIRON_DECL -extern char **environ; -#endif - -static char * const forbid[] = { - "BASH_ENV=", /* GNU creeping featurism strikes again... */ - "ENV=", - "HOME=", - "IFS=", - "KRB_CONF=", - "LD_", /* anything with the LD_ prefix */ - "LIBPATH=", - "MAIL=", - "NLSPATH=", - "PATH=", - "SHELL=", - "SHLIB_PATH=", - (char *) 0 -}; - -/* these are allowed, but with no slashes inside - (to work around security problems in GNU gettext) */ -static char * const noslash[] = { - "LANG=", - "LANGUAGE=", - "LC_", /* anything with the LC_ prefix */ - (char *) 0 -}; - - -struct ul_env_list { - char *env; - struct ul_env_list *next; -}; - -/* - * Saves @name env.varable to @ls, returns pointer to the new head of the list. - */ -static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str) -{ - struct ul_env_list *ls; - char *p; - size_t sz = 0; - - if (!str || !*str) - return ls0; - - sz = strlen(str) + 1; - p = malloc(sizeof(struct ul_env_list) + sz); - - ls = (struct ul_env_list *) p; - p += sizeof(struct ul_env_list); - memcpy(p, str, sz); - ls->env = p; - - ls->next = ls0; - return ls; -} - -/* - * Use setenv() for all stuff in @ls. - * - * It would be possible to use putenv(), but we want to keep @ls free()-able. - */ -int env_list_setenv(struct ul_env_list *ls) -{ - int rc = 0; - - while (ls && rc == 0) { - if (ls->env) { - char *val = strchr(ls->env, '='); - if (!val) - continue; - *val = '\0'; - rc = setenv(ls->env, val + 1, 0); - *val = '='; - } - ls = ls->next; - } - return rc; -} - -void env_list_free(struct ul_env_list *ls) -{ - while (ls) { - struct ul_env_list *x = ls; - ls = ls->next; - free(x); - } -} - -/* - * Removes unwanted variables from environ[]. If @ls is not NULL than stores - * unwnated variables to the list. - */ -void __sanitize_env(struct ul_env_list **org) -{ - char **envp = environ; - char * const *bad; - char **cur; - int last = 0; - - for (cur = envp; *cur; cur++) - last++; - - for (cur = envp; *cur; cur++) { - for (bad = forbid; *bad; bad++) { - if (strncmp(*cur, *bad, strlen(*bad)) == 0) { - if (org) - *org = env_list_add(*org, *cur); - last = remote_entry(envp, cur - envp, last); - cur--; - break; - } - } - } - - for (cur = envp; *cur; cur++) { - for (bad = noslash; *bad; bad++) { - if (strncmp(*cur, *bad, strlen(*bad)) != 0) - continue; - if (!strchr(*cur, '/')) - continue; /* OK */ - if (org) - *org = env_list_add(*org, *cur); - last = remote_entry(envp, cur - envp, last); - cur--; - break; - } - } -} - -void sanitize_env(void) -{ - __sanitize_env(NULL); -} - -char *safe_getenv(const char *arg) -{ - uid_t ruid = getuid(); - - if (ruid != 0 || (ruid != geteuid()) || (getgid() != getegid())) - return NULL; -#ifdef HAVE_PRCTL - if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) - return NULL; -#else -#if (defined(linux) && defined(SYS_prctl)) - if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) - return NULL; -#endif -#endif -#ifdef HAVE_SECURE_GETENV -return secure_getenv(arg); -#elif HAVE___SECURE_GETENV - return __secure_getenv(arg); -#else - return getenv(arg); -#endif -} - -#ifdef TEST_PROGRAM -int main(void) -{ - char *const *bad; - char copy[32]; - char *p; - int retval = EXIT_SUCCESS; - struct ul_env_list *removed = NULL; - - for (bad = forbid; *bad; bad++) { - strcpy(copy, *bad); - p = strchr(copy, '='); - if (p) - *p = '\0'; - setenv(copy, copy, 1); - } - - /* removed */ - __sanitize_env(&removed); - - /* check removal */ - for (bad = forbid; *bad; bad++) { - strcpy(copy, *bad); - p = strchr(copy, '='); - if (p) - *p = '\0'; - p = getenv(copy); - if (p) { - warnx("%s was not removed", copy); - retval = EXIT_FAILURE; - } - } - - /* restore removed */ - env_list_setenv(removed); - - /* check restore */ - for (bad = forbid; *bad; bad++) { - strcpy(copy, *bad); - p = strchr(copy, '='); - if (p) - *p = '\0'; - p = getenv(copy); - if (!p) { - warnx("%s was not restored", copy); - retval = EXIT_FAILURE; - } - } - - env_list_free(removed); - - return retval; -} -#endif diff --git a/utils/lib/exec_shell.c b/utils/lib/exec_shell.c deleted file mode 100644 index 18798eb..0000000 --- a/utils/lib/exec_shell.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * exec_shell() - launch a shell, else exit! - * - * 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; either version 2, or (at your option) any - * later version. - * - * This program 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. - * - * 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 "nls.h" -#include "c.h" -#include "xalloc.h" - -#include "exec_shell.h" - -#define DEFAULT_SHELL "/bin/sh" - -void __attribute__((__noreturn__)) exec_shell(void) -{ - const char *shell = getenv("SHELL"); - char *shellc; - const char *shell_basename; - char *arg0; - - if (!shell) - shell = DEFAULT_SHELL; - - shellc = xstrdup(shell); - shell_basename = basename(shellc); - arg0 = xmalloc(strlen(shell_basename) + 2); - arg0[0] = '-'; - strcpy(arg0 + 1, shell_basename); - - execl(shell, arg0, NULL); - errexec(shell); -} diff --git a/utils/lib/fileutils.c b/utils/lib/fileutils.c deleted file mode 100644 index 3ca43c1..0000000 --- a/utils/lib/fileutils.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2012 Sami Kerola - */ - -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "fileutils.h" -#include "pathnames.h" - -int mkstemp_cloexec(char *template) -{ -#ifdef HAVE_MKOSTEMP - return mkostemp(template, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC); -#else - int fd, old_flags, errno_save; - - fd = mkstemp(template); - if (fd < 0) - return fd; - - old_flags = fcntl(fd, F_GETFD, 0); - if (old_flags < 0) - goto unwind; - if (fcntl(fd, F_SETFD, old_flags | O_CLOEXEC) < 0) - goto unwind; - - return fd; - -unwind: - errno_save = errno; - unlink(template); - close(fd); - errno = errno_save; - - return -1; -#endif -} - -/* Create open temporary file in safe way. Please notice that the - * file permissions are -rw------- by default. */ -int xmkstemp(char **tmpname, const char *dir, const char *prefix) -{ - char *localtmp; - const char *tmpenv; - mode_t old_mode; - int fd, rc; - - /* Some use cases must be capable of being moved atomically - * with rename(2), which is the reason why dir is here. */ - tmpenv = dir ? dir : getenv("TMPDIR"); - if (!tmpenv) - tmpenv = _PATH_TMP; - - rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, prefix); - if (rc < 0) - return -1; - - old_mode = umask(077); - fd = mkstemp_cloexec(localtmp); - umask(old_mode); - if (fd == -1) { - free(localtmp); - localtmp = NULL; - } - *tmpname = localtmp; - return fd; -} - -int dup_fd_cloexec(int oldfd, int lowfd) -{ - int fd, flags, errno_save; - -#ifdef F_DUPFD_CLOEXEC - fd = fcntl(oldfd, F_DUPFD_CLOEXEC, lowfd); - if (fd >= 0) - return fd; -#endif - - fd = dup(oldfd); - if (fd < 0) - return fd; - - flags = fcntl(fd, F_GETFD); - if (flags < 0) - goto unwind; - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) - goto unwind; - - return fd; - -unwind: - errno_save = errno; - close(fd); - errno = errno_save; - - return -1; -} - -/* - * portable getdtablesize() - */ -int get_fd_tabsize(void) -{ - int m; - -#if defined(HAVE_GETDTABLESIZE) - m = getdtablesize(); -#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) - struct rlimit rl; - - getrlimit(RLIMIT_NOFILE, &rl); - m = rl.rlim_cur; -#elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) - m = sysconf(_SC_OPEN_MAX); -#else - m = OPEN_MAX; -#endif - return m; -} - -static inline int in_set(int x, const int set[], size_t setsz) -{ - size_t i; - - for (i = 0; i < setsz; i++) { - if (set[i] == x) - return 1; - } - return 0; -} - -void close_all_fds(const int exclude[], size_t exsz) -{ - struct dirent *d; - DIR *dir; - - dir = opendir(_PATH_PROC_FDDIR); - if (dir) { - while ((d = xreaddir(dir))) { - char *end; - int fd; - - errno = 0; - fd = strtol(d->d_name, &end, 10); - - if (errno || end == d->d_name || !end || *end) - continue; - if (dirfd(dir) == fd) - continue; - if (in_set(fd, exclude, exsz)) - continue; - close(fd); - } - closedir(dir); - } else { - int fd, tbsz = get_fd_tabsize(); - - for (fd = 0; fd < tbsz; fd++) { - if (!in_set(fd, exclude, exsz)) - close(fd); - } - } -} - -#ifdef TEST_PROGRAM_FILEUTILS -int main(int argc, char *argv[]) -{ - if (argc < 2) - errx(EXIT_FAILURE, "Usage %s --{mkstemp,close-fds}", argv[0]); - - if (strcmp(argv[1], "--mkstemp") == 0) { - FILE *f; - char *tmpname; - f = xfmkstemp(&tmpname, NULL, "test"); - unlink(tmpname); - free(tmpname); - fclose(f); - - } else if (strcmp(argv[1], "--close-fds") == 0) { - static const int wanted_fds[] = { - STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO - }; - - ignore_result( dup(STDIN_FILENO) ); - ignore_result( dup(STDIN_FILENO) ); - ignore_result( dup(STDIN_FILENO) ); - - close_all_fds(wanted_fds, ARRAY_SIZE(wanted_fds)); - } - return EXIT_SUCCESS; -} -#endif - - -int mkdir_p(const char *path, mode_t mode) -{ - char *p, *dir; - int rc = 0; - - if (!path || !*path) - return -EINVAL; - - dir = p = strdup(path); - if (!dir) - return -ENOMEM; - - if (*p == '/') - p++; - - while (p && *p) { - char *e = strchr(p, '/'); - if (e) - *e = '\0'; - if (*p) { - rc = mkdir(dir, mode); - if (rc && errno != EEXIST) - break; - rc = 0; - } - if (!e) - break; - *e = '/'; - p = e + 1; - } - - free(dir); - return rc; -} - -/* returns basename and keeps dirname in the @path, if @path is "/" (root) - * then returns empty string */ -char *stripoff_last_component(char *path) -{ - char *p = path ? strrchr(path, '/') : NULL; - - if (!p) - return NULL; - *p = '\0'; - return p + 1; -} diff --git a/utils/lib/idcache.c b/utils/lib/idcache.c deleted file mode 100644 index 5550223..0000000 --- a/utils/lib/idcache.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak - */ -#include -#include -#include -#include - -#include "c.h" -#include "idcache.h" - -struct identry *get_id(struct idcache *ic, unsigned long int id) -{ - struct identry *ent; - - if (!ic) - return NULL; - - for (ent = ic->ent; ent; ent = ent->next) { - if (ent->id == id) - return ent; - } - - return NULL; -} - -struct idcache *new_idcache(void) -{ - return calloc(1, sizeof(struct idcache)); -} - -void free_idcache(struct idcache *ic) -{ - struct identry *ent = ic->ent; - - while (ent) { - struct identry *next = ent->next; - free(ent->name); - free(ent); - ent = next; - } - - free(ic); -} - -static void add_id(struct idcache *ic, char *name, unsigned long int id) -{ - struct identry *ent, *x; - int w = 0; - - ent = calloc(1, sizeof(struct identry)); - if (!ent) - return; - ent->id = id; - - if (name) { -#ifdef HAVE_WIDECHAR - wchar_t wc[LOGIN_NAME_MAX + 1]; - - if (mbstowcs(wc, name, LOGIN_NAME_MAX) > 0) { - wc[LOGIN_NAME_MAX] = '\0'; - w = wcswidth(wc, LOGIN_NAME_MAX); - } - else -#endif - w = strlen(name); - } - - /* note, we ignore names with non-printable widechars */ - if (w > 0) { - ent->name = strdup(name); - if (!ent->name) { - free(ent); - return; - } - } else { - if (asprintf(&ent->name, "%lu", id) < 0) { - free(ent); - return; - } - } - - for (x = ic->ent; x && x->next; x = x->next); - - if (x) - x->next = ent; - else - ic->ent = ent; - - if (w <= 0) - w = ent->name ? strlen(ent->name) : 0; - ic->width = ic->width < w ? w : ic->width; -} - -void add_uid(struct idcache *cache, unsigned long int id) -{ - struct identry *ent= get_id(cache, id); - - if (!ent) { - struct passwd *pw = getpwuid((uid_t) id); - add_id(cache, pw ? pw->pw_name : NULL, id); - } -} - -void add_gid(struct idcache *cache, unsigned long int id) -{ - struct identry *ent = get_id(cache, id); - - if (!ent) { - struct group *gr = getgrgid((gid_t) id); - add_id(cache, gr ? gr->gr_name : NULL, id); - } -} - diff --git a/utils/lib/ismounted.c b/utils/lib/ismounted.c deleted file mode 100644 index 9a20b23..0000000 --- a/utils/lib/ismounted.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * ismounted.c --- Check to see if the filesystem was mounted - * - * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o. - * - * This file may be redistributed under the terms of the GNU Public - * License. - */ -#include -#include -#include -#include -#include -#ifdef HAVE_MNTENT_H -#include -#endif -#include -#include -#include -#include - -#ifndef __linux__ -# ifdef HAVE_SYS_UCRED_H -# include -# endif -# ifdef HAVE_SYS_MOUNT_H -# include -# endif -#endif - -#include "pathnames.h" -#include "strutils.h" -#include "ismounted.h" -#include "c.h" -#ifdef __linux__ -# include "loopdev.h" -#endif - - - -#ifdef HAVE_MNTENT_H -/* - * Helper function which checks a file in /etc/mtab format to see if a - * filesystem is mounted. Returns an error if the file doesn't exist - * or can't be opened. - */ -static int check_mntent_file(const char *mtab_file, const char *file, - int *mount_flags, char *mtpt, int mtlen) -{ - struct mntent *mnt; - struct stat st_buf; - int retval = 0; - dev_t file_dev=0, file_rdev=0; - ino_t file_ino=0; - FILE *f; - int fd; - - *mount_flags = 0; - if ((f = setmntent (mtab_file, "r")) == NULL) - return errno; - - if (stat(file, &st_buf) == 0) { - if (S_ISBLK(st_buf.st_mode)) { -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - file_rdev = st_buf.st_rdev; -#endif /* __GNU__ */ - } else { - file_dev = st_buf.st_dev; - file_ino = st_buf.st_ino; - } - } - - while ((mnt = getmntent (f)) != NULL) { - if (mnt->mnt_fsname[0] != '/') - continue; - if (strcmp(file, mnt->mnt_fsname) == 0) - break; - if (stat(mnt->mnt_fsname, &st_buf) != 0) - continue; - - if (S_ISBLK(st_buf.st_mode)) { -#ifndef __GNU__ - if (file_rdev && file_rdev == st_buf.st_rdev) - break; -#ifdef __linux__ - /* maybe the file is loopdev backing file */ - if (file_dev - && major(st_buf.st_rdev) == LOOPDEV_MAJOR - && loopdev_is_used(mnt->mnt_fsname, file, 0, 0, 0)) - break; -#endif /* __linux__ */ -#endif /* __GNU__ */ - } else { - if (file_dev && ((file_dev == st_buf.st_dev) && - (file_ino == st_buf.st_ino))) - break; - } - } - - if (mnt == NULL) { -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - /* - * Do an extra check to see if this is the root device. We - * can't trust /etc/mtab, and /proc/mounts will only list - * /dev/root for the root filesystem. Argh. Instead we - * check if the given device has the same major/minor number - * as the device that the root directory is on. - */ - if (file_rdev && stat("/", &st_buf) == 0 && - st_buf.st_dev == file_rdev) { - *mount_flags = MF_MOUNTED; - if (mtpt) - xstrncpy(mtpt, "/", mtlen); - goto is_root; - } -#endif /* __GNU__ */ - goto errout; - } -#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ - /* Validate the entry in case /etc/mtab is out of date */ - /* - * We need to be paranoid, because some broken distributions - * (read: Slackware) don't initialize /etc/mtab before checking - * all of the non-root filesystems on the disk. - */ - if (stat(mnt->mnt_dir, &st_buf) < 0) { - retval = errno; - if (retval == ENOENT) { -#ifdef DEBUG - printf("Bogus entry in %s! (%s does not exist)\n", - mtab_file, mnt->mnt_dir); -#endif /* DEBUG */ - retval = 0; - } - goto errout; - } - if (file_rdev && (st_buf.st_dev != file_rdev)) { -#ifdef DEBUG - printf("Bogus entry in %s! (%s not mounted on %s)\n", - mtab_file, file, mnt->mnt_dir); -#endif /* DEBUG */ - goto errout; - } -#endif /* __GNU__ */ - *mount_flags = MF_MOUNTED; - -#ifdef MNTOPT_RO - /* Check to see if the ro option is set */ - if (hasmntopt(mnt, MNTOPT_RO)) - *mount_flags |= MF_READONLY; -#endif - - if (mtpt) - xstrncpy(mtpt, mnt->mnt_dir, mtlen); - /* - * Check to see if we're referring to the root filesystem. - * If so, do a manual check to see if we can open /etc/mtab - * read/write, since if the root is mounted read/only, the - * contents of /etc/mtab may not be accurate. - */ - if (!strcmp(mnt->mnt_dir, "/")) { -is_root: -#define TEST_FILE "/.ismount-test-file" - *mount_flags |= MF_ISROOT; - fd = open(TEST_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0600); - if (fd < 0) { - if (errno == EROFS) - *mount_flags |= MF_READONLY; - } else - close(fd); - (void) unlink(TEST_FILE); - } - retval = 0; -errout: - endmntent (f); - return retval; -} - -static int check_mntent(const char *file, int *mount_flags, - char *mtpt, int mtlen) -{ - int retval; - -#ifdef DEBUG - retval = check_mntent_file("/tmp/mtab", file, mount_flags, - mtpt, mtlen); - if (retval == 0) - return 0; -#endif /* DEBUG */ -#ifdef __linux__ - retval = check_mntent_file("/proc/mounts", file, mount_flags, - mtpt, mtlen); - if (retval == 0 && (*mount_flags != 0)) - return 0; - if (access("/proc/mounts", R_OK) == 0) { - *mount_flags = 0; - return retval; - } -#endif /* __linux__ */ -#if defined(MOUNTED) || defined(_PATH_MOUNTED) -#ifndef MOUNTED -#define MOUNTED _PATH_MOUNTED -#endif /* MOUNTED */ - retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); - return retval; -#else - *mount_flags = 0; - return 0; -#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ -} - -#else -#if defined(HAVE_GETMNTINFO) - -static int check_getmntinfo(const char *file, int *mount_flags, - char *mtpt, int mtlen) -{ - struct statfs *mp; - int len, n; - const char *s1; - char *s2; - - n = getmntinfo(&mp, MNT_NOWAIT); - if (n == 0) - return errno; - - len = sizeof(_PATH_DEV) - 1; - s1 = file; - if (strncmp(_PATH_DEV, s1, len) == 0) - s1 += len; - - *mount_flags = 0; - while (--n >= 0) { - s2 = mp->f_mntfromname; - if (strncmp(_PATH_DEV, s2, len) == 0) { - s2 += len - 1; - *s2 = 'r'; - } - if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { - *mount_flags = MF_MOUNTED; - break; - } - ++mp; - } - if (mtpt) - xstrncpy(mtpt, mp->f_mntonname, mtlen); - return 0; -} -#endif /* HAVE_GETMNTINFO */ -#endif /* HAVE_MNTENT_H */ - -/* - * Check to see if we're dealing with the swap device. - */ -static int is_swap_device(const char *file) -{ - FILE *f; - char buf[1024], *cp; - dev_t file_dev; - struct stat st_buf; - int ret = 0; - - file_dev = 0; -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - if ((stat(file, &st_buf) == 0) && - S_ISBLK(st_buf.st_mode)) - file_dev = st_buf.st_rdev; -#endif /* __GNU__ */ - - if (!(f = fopen("/proc/swaps", "r" UL_CLOEXECSTR))) - return 0; - /* Skip the first line */ - if (!fgets(buf, sizeof(buf), f)) - goto leave; - if (*buf && strncmp(buf, "Filename\t", 9) != 0) - /* Linux <=2.6.19 contained a bug in the /proc/swaps - * code where the header would not be displayed - */ - goto valid_first_line; - - while (fgets(buf, sizeof(buf), f)) { -valid_first_line: - if ((cp = strchr(buf, ' ')) != NULL) - *cp = 0; - if ((cp = strchr(buf, '\t')) != NULL) - *cp = 0; - if (strcmp(buf, file) == 0) { - ret++; - break; - } -#ifndef __GNU__ - if (file_dev && (stat(buf, &st_buf) == 0) && - S_ISBLK(st_buf.st_mode) && - file_dev == st_buf.st_rdev) { - ret++; - break; - } -#endif /* __GNU__ */ - } - -leave: - fclose(f); - return ret; -} - - -/* - * check_mount_point() fills determines if the device is mounted or otherwise - * busy, and fills in mount_flags with one or more of the following flags: - * MF_MOUNTED, MF_ISROOT, MF_READONLY, MF_SWAP, and MF_BUSY. If mtpt is - * non-NULL, the directory where the device is mounted is copied to where mtpt - * is pointing, up to mtlen characters. - */ -#ifdef __TURBOC__ - #pragma argsused -#endif -int check_mount_point(const char *device, int *mount_flags, - char *mtpt, int mtlen) -{ - int retval = 0; - - if (is_swap_device(device)) { - *mount_flags = MF_MOUNTED | MF_SWAP; - if (mtpt && mtlen) - xstrncpy(mtpt, "[SWAP]", mtlen); - } else { -#ifdef HAVE_MNTENT_H - retval = check_mntent(device, mount_flags, mtpt, mtlen); -#else -#ifdef HAVE_GETMNTINFO - retval = check_getmntinfo(device, mount_flags, mtpt, mtlen); -#else -#ifdef __GNUC__ - #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" -#endif - *mount_flags = 0; -#endif /* HAVE_GETMNTINFO */ -#endif /* HAVE_MNTENT_H */ - } - if (retval) - return retval; - -#ifdef __linux__ /* This only works on Linux 2.6+ systems */ - { - struct stat st_buf; - int fd; - if ((stat(device, &st_buf) != 0) || - !S_ISBLK(st_buf.st_mode)) - return 0; - fd = open(device, O_RDONLY|O_EXCL|O_CLOEXEC); - if (fd < 0) { - if (errno == EBUSY) - *mount_flags |= MF_BUSY; - } else - close(fd); - } -#endif - - return 0; -} - -int is_mounted(const char *file) -{ - int retval; - int mount_flags = 0; - - retval = check_mount_point(file, &mount_flags, NULL, 0); - if (retval) - return 0; - return mount_flags & MF_MOUNTED; -} - -#ifdef TEST_PROGRAM_ISMOUNTED -int main(int argc, char **argv) -{ - int flags = 0; - char devname[PATH_MAX]; - - if (argc < 2) { - fprintf(stderr, "Usage: %s device\n", argv[0]); - return EXIT_FAILURE; - } - - if (check_mount_point(argv[1], &flags, devname, sizeof(devname)) == 0 && - (flags & MF_MOUNTED)) { - if (flags & MF_SWAP) - printf("used swap device\n"); - else - printf("mounted on %s\n", devname); - return EXIT_SUCCESS; - } - - printf("not mounted\n"); - return EXIT_FAILURE; -} -#endif /* DEBUG */ diff --git a/utils/lib/langinfo.c b/utils/lib/langinfo.c deleted file mode 100644 index a200085..0000000 --- a/utils/lib/langinfo.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This is callback solution for systems without nl_langinfo(), this function - * returns hardcoded and on locale setting indepndent value. - * - * See langinfo.h man page for more details. - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Copyright (C) 2010 Karel Zak - */ -#include "nls.h" - -char *langinfo_fallback(nl_item item) -{ - switch (item) { - case CODESET: - return "ISO-8859-1"; - case THOUSEP: - return ","; - case D_T_FMT: - case ERA_D_T_FMT: - return "%a %b %e %H:%M:%S %Y"; - case D_FMT: - case ERA_D_FMT: - return "%m/%d/%y"; - case T_FMT: - case ERA_T_FMT: - return "%H:%M:%S"; - case T_FMT_AMPM: - return "%I:%M:%S %p"; - case AM_STR: - return "AM"; - case PM_STR: - return "PM"; - case DAY_1: - return "Sunday"; - case DAY_2: - return "Monday"; - case DAY_3: - return "Tuesday"; - case DAY_4: - return "Wednesday"; - case DAY_5: - return "Thursday"; - case DAY_6: - return "Friday"; - case DAY_7: - return "Saturday"; - case ABDAY_1: - return "Sun"; - case ABDAY_2: - return "Mon"; - case ABDAY_3: - return "Tue"; - case ABDAY_4: - return "Wed"; - case ABDAY_5: - return "Thu"; - case ABDAY_6: - return "Fri"; - case ABDAY_7: - return "Sat"; - case MON_1: - return "January"; - case MON_2: - return "February"; - case MON_3: - return "March"; - case MON_4: - return "April"; - case MON_5: - return "May"; - case MON_6: - return "June"; - case MON_7: - return "July"; - case MON_8: - return "August"; - case MON_9: - return "September"; - case MON_10: - return "October"; - case MON_11: - return "November"; - case MON_12: - return "December"; - case ABMON_1: - return "Jan"; - case ABMON_2: - return "Feb"; - case ABMON_3: - return "Mar"; - case ABMON_4: - return "Apr"; - case ABMON_5: - return "May"; - case ABMON_6: - return "Jun"; - case ABMON_7: - return "Jul"; - case ABMON_8: - return "Aug"; - case ABMON_9: - return "Sep"; - case ABMON_10: - return "Oct"; - case ABMON_11: - return "Nov"; - case ABMON_12: - return "Dec"; - case ALT_DIGITS: - return "\0\0\0\0\0\0\0\0\0\0"; - case CRNCYSTR: - return "-"; - case YESEXPR: - return "^[yY]"; - case NOEXPR: - return "^[nN]"; - default: - return ""; - } -} - diff --git a/utils/lib/linux_version.c b/utils/lib/linux_version.c deleted file mode 100644 index 137bbe7..0000000 --- a/utils/lib/linux_version.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include - -#include "c.h" -#include "linux_version.h" - -int get_linux_version (void) -{ - static int kver = -1; - struct utsname uts; - int x = 0, y = 0, z = 0; - int n; - - if (kver != -1) - return kver; - if (uname(&uts)) - return kver = 0; - - n = sscanf(uts.release, "%d.%d.%d", &x, &y, &z); - if (n < 1 || n > 3) - return kver = 0; - - return kver = KERNEL_VERSION(x, y, z); -} - -#ifdef TEST_PROGRAM_LINUXVERSION -# include -int main(int argc, char *argv[]) -{ - int rc = EXIT_FAILURE; - - if (argc == 1) { - printf("Linux version: %d\n", get_linux_version()); - rc = EXIT_SUCCESS; - - } else if (argc == 5) { - const char *oper = argv[1]; - - int x = atoi(argv[2]), - y = atoi(argv[3]), - z = atoi(argv[4]); - int kver = get_linux_version(); - int uver = KERNEL_VERSION(x, y, z); - - if (strcmp(oper, "==") == 0) - rc = kver == uver; - else if (strcmp(oper, "<=") == 0) - rc = kver <= uver; - else if (strcmp(oper, ">=") == 0) - rc = kver >= uver; - else - errx(EXIT_FAILURE, "unsupported operator"); - - if (rc) - printf("match\n"); - else - printf("not-match [%d %s %d, x.y.z: %d.%d.%d]\n", - kver, oper, uver, x, y, z); - - rc = rc ? EXIT_SUCCESS : EXIT_FAILURE; - - } else - fprintf(stderr, "Usage:\n" - " %s [ ]\n" - "supported operators:\n" - " ==, <=, >=\n", - program_invocation_short_name); - - return rc; -} -#endif diff --git a/utils/lib/loopdev.c b/utils/lib/loopdev.c deleted file mode 100644 index be4e486..0000000 --- a/utils/lib/loopdev.c +++ /dev/null @@ -1,1914 +0,0 @@ - -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak - * - * -- based on mount/losetup.c - * - * Simple library for work with loop devices. - * - * - requires kernel 2.6.x - * - reads info from /sys/block/loop/loop/ (new kernels) - * - reads info by ioctl - * - supports *unlimited* number of loop devices - * - supports /dev/xloop as well as /dev/xloop/ - * - minimize overhead (fd, loopinfo, ... are shared for all operations) - * - setup (associate device and backing file) - * - delete (dis-associate file) - * - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported - * - extendible - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "linux_version.h" -#include "c.h" -#include "sysfs.h" -#include "pathnames.h" -#include "loopdev.h" -#include "canonicalize.h" -#include "blkdev.h" -#include "debug.h" - -/* - * Debug stuff (based on include/debug.h) - */ -static UL_DEBUG_DEFINE_MASK(loopdev); -UL_DEBUG_DEFINE_MASKNAMES(loopdev) = UL_DEBUG_EMPTY_MASKNAMES; - -#define XLOOPDEV_DEBUG_INIT (1 << 1) -#define XLOOPDEV_DEBUG_CXT (1 << 2) -#define XLOOPDEV_DEBUG_ITER (1 << 3) -#define XLOOPDEV_DEBUG_SETUP (1 << 4) - -#define DBG(m, x) __UL_DBG(loopdev, XLOOPDEV_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(loopdev, XLOOPDEV_DEBUG_, m, x) - -#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(loopdev) -#include "debugobj.h" - -static void loopdev_init_debug(void) -{ - if (loopdev_debug_mask) - return; - __UL_INIT_DEBUG_FROM_ENV(loopdev, XLOOPDEV_DEBUG_, 0, XLOOPDEV_DEBUG); -} - -/* - * see loopcxt_init() - */ -#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL)) -#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \ - && !loopcxt_ioctl_enabled(_lc) - -/* - * @lc: context - * @device: device name, absolute device path or NULL to reset the current setting - * - * Sets device, absolute paths (e.g. "/dev/xloop") are unchanged, device - * names ("xloop") are converted to the path (/dev/xloop or to - * /dev/xloop/) - * - * This sets the device name, but does not check if the device exists! - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) -{ - if (!lc) - return -EINVAL; - - if (lc->fd >= 0) { - close(lc->fd); - DBG(CXT, ul_debugobj(lc, "closing old open fd")); - } - lc->fd = -1; - lc->mode = 0; - lc->blocksize = 0; - lc->has_info = 0; - lc->info_failed = 0; - *lc->device = '\0'; - memset(&lc->info, 0, sizeof(lc->info)); - - /* set new */ - if (device) { - if (*device != '/') { - const char *dir = _PATH_DEV; - - /* compose device name for /dev/xloop or /dev/xloop/ */ - if (lc->flags & LOOPDEV_FL_DEVSUBDIR) { - if (strlen(device) <= 5) - return -1; - device += 5; - dir = _PATH_DEV_LOOP "/"; /* _PATH_DEV uses tailing slash */ - } - snprintf(lc->device, sizeof(lc->device), "%s%s", - dir, device); - } else - xstrncpy(lc->device, device, sizeof(lc->device)); - - DBG(CXT, ul_debugobj(lc, "%s name assigned", device)); - } - - ul_unref_path(lc->sysfs); - lc->sysfs = NULL; - return 0; -} - -int loopcxt_has_device(struct loopdev_cxt *lc) -{ - return lc && *lc->device; -} - -/* - * @lc: context - * @flags: LOOPDEV_FL_* flags - * - * Initialize loop handler. - * - * We have two sets of the flags: - * - * * LOOPDEV_FL_* flags control loopcxt_* API behavior - * - * * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls - * - * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2) - * syscall to open loop device. By default is the device open read-only. - * - * The exception is loopcxt_setup_device(), where the device is open read-write - * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()). - * - * Returns: <0 on error, 0 on success. - */ -int loopcxt_init(struct loopdev_cxt *lc, int flags) -{ - int rc; - struct stat st; - struct loopdev_cxt dummy = UL_LOOPDEVCXT_EMPTY; - - if (!lc) - return -EINVAL; - - loopdev_init_debug(); - DBG(CXT, ul_debugobj(lc, "initialize context")); - - memcpy(lc, &dummy, sizeof(dummy)); - lc->flags = flags; - - rc = loopcxt_set_device(lc, NULL); - if (rc) - return rc; - - if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) { - lc->flags |= LOOPDEV_FL_NOSYSFS; - lc->flags &= ~LOOPDEV_FL_NOIOCTL; - DBG(CXT, ul_debugobj(lc, "init: disable /sys usage")); - } - - if (!(lc->flags & LOOPDEV_FL_NOSYSFS) && - get_linux_version() >= KERNEL_VERSION(2,6,37)) { - /* - * Use only sysfs for basic information about loop devices - */ - lc->flags |= LOOPDEV_FL_NOIOCTL; - DBG(CXT, ul_debugobj(lc, "init: ignore ioctls")); - } - - if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) { - lc->flags |= LOOPDEV_FL_CONTROL; - DBG(CXT, ul_debugobj(lc, "init: xloop-control detected ")); - } - - return 0; -} - -/* - * @lc: context - * - * Deinitialize loop context - */ -void loopcxt_deinit(struct loopdev_cxt *lc) -{ - int errsv = errno; - - if (!lc) - return; - - DBG(CXT, ul_debugobj(lc, "de-initialize")); - - free(lc->filename); - lc->filename = NULL; - - ignore_result( loopcxt_set_device(lc, NULL) ); - loopcxt_deinit_iterator(lc); - - errno = errsv; -} - -/* - * @lc: context - * - * Returns newly allocated device path. - */ -char *loopcxt_strdup_device(struct loopdev_cxt *lc) -{ - if (!lc || !*lc->device) - return NULL; - return strdup(lc->device); -} - -/* - * @lc: context - * - * Returns pointer device name in the @lc struct. - */ -const char *loopcxt_get_device(struct loopdev_cxt *lc) -{ - return lc && *lc->device ? lc->device : NULL; -} - -/* - * @lc: context - * - * Returns pointer to the sysfs context (see lib/sysfs.c) - */ -static struct path_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc) -{ - if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS)) - return NULL; - - if (!lc->sysfs) { - dev_t devno = sysfs_devname_to_devno(lc->device); - if (!devno) { - DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno")); - return NULL; - } - - lc->sysfs = ul_new_sysfs_path(devno, NULL, NULL); - if (!lc->sysfs) - DBG(CXT, ul_debugobj(lc, "sysfs: init failed")); - } - - return lc->sysfs; -} - -/* - * @lc: context - * - * Returns: file descriptor to the open loop device or <0 on error. The mode - * depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is - * read-only. - */ -int loopcxt_get_fd(struct loopdev_cxt *lc) -{ - if (!lc || !*lc->device) - return -EINVAL; - - if (lc->fd < 0) { - lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY; - lc->fd = open(lc->device, lc->mode | O_CLOEXEC); - DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device, - lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro")); - } - return lc->fd; -} - -int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode) -{ - if (!lc) - return -EINVAL; - - lc->fd = fd; - lc->mode = mode; - return 0; -} - -/* - * @lc: context - * @flags: LOOPITER_FL_* flags - * - * Iterator can be used to scan list of the free or used loop devices. - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags) -{ - struct loopdev_iter *iter; - struct stat st; - - if (!lc) - return -EINVAL; - - - iter = &lc->iter; - DBG(ITER, ul_debugobj(iter, "initialize")); - - /* always zeroize - */ - memset(iter, 0, sizeof(*iter)); - iter->ncur = -1; - iter->flags = flags; - iter->default_check = 1; - - if (!lc->extra_check) { - /* - * Check for /dev/xloop/ subdirectory - */ - if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) && - stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode)) - lc->flags |= LOOPDEV_FL_DEVSUBDIR; - - lc->extra_check = 1; - } - return 0; -} - -/* - * @lc: context - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_deinit_iterator(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter; - - if (!lc) - return -EINVAL; - - iter = &lc->iter; - DBG(ITER, ul_debugobj(iter, "de-initialize")); - - free(iter->minors); - if (iter->proc) - fclose(iter->proc); - if (iter->sysblock) - closedir(iter->sysblock); - - memset(iter, 0, sizeof(*iter)); - return 0; -} - -/* - * Same as loopcxt_set_device, but also checks if the device is - * associated with any file. - * - * Returns: <0 on error, 0 on success, 1 device does not match with - * LOOPITER_FL_{USED,FREE} flags. - */ -static int loopiter_set_device(struct loopdev_cxt *lc, const char *device) -{ - int rc = loopcxt_set_device(lc, device); - int used; - - if (rc) - return rc; - - if (!(lc->iter.flags & LOOPITER_FL_USED) && - !(lc->iter.flags & LOOPITER_FL_FREE)) - return 0; /* caller does not care about device status */ - - if (!is_loopdev(lc->device)) { - DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device)); - return -errno; - } - - DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device)); - - used = loopcxt_get_offset(lc, NULL) == 0; - - if ((lc->iter.flags & LOOPITER_FL_USED) && used) - return 0; - - if ((lc->iter.flags & LOOPITER_FL_FREE) && !used) - return 0; - - DBG(ITER, ul_debugobj(&lc->iter, "failed to use %s device", lc->device)); - - ignore_result( loopcxt_set_device(lc, NULL) ); - return 1; -} - -static int cmpnum(const void *p1, const void *p2) -{ - return (((* (const int *) p1) > (* (const int *) p2)) - - ((* (const int *) p1) < (* (const int *) p2))); -} - -/* - * The classic scandir() is more expensive and less portable. - * We needn't full loop device names -- loop numbers (loop) - * are enough. - */ -static int loop_scandir(const char *dirname, int **ary, int hasprefix) -{ - DIR *dir; - struct dirent *d; - unsigned int n, count = 0, arylen = 0; - - if (!dirname || !ary) - return 0; - - DBG(ITER, ul_debug("scan dir: %s", dirname)); - - dir = opendir(dirname); - if (!dir) - return 0; - free(*ary); - *ary = NULL; - - while((d = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN && - d->d_type != DT_LNK) - continue; -#endif - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) - continue; - - if (hasprefix) { - /* /dev/xloop */ - if (sscanf(d->d_name, "xloop%u", &n) != 1) - continue; - } else { - /* /dev/xloop/ */ - char *end = NULL; - - errno = 0; - n = strtol(d->d_name, &end, 10); - if (d->d_name == end || (end && *end) || errno) - continue; - } - if (n < LOOPDEV_DEFAULT_NNODES) - continue; /* ignore xloop<0..7> */ - - if (count + 1 > arylen) { - int *tmp; - - arylen += 1; - - tmp = realloc(*ary, arylen * sizeof(int)); - if (!tmp) { - free(*ary); - *ary = NULL; - closedir(dir); - return -1; - } - *ary = tmp; - } - if (*ary) - (*ary)[count++] = n; - } - if (count && *ary) - qsort(*ary, count, sizeof(int), cmpnum); - - closedir(dir); - return count; -} - -/* - * Set the next *used* loop device according to /proc/partitions. - * - * Loop devices smaller than 512 bytes are invisible for this function. - */ -static int loopcxt_next_from_proc(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter = &lc->iter; - char buf[BUFSIZ]; - - DBG(ITER, ul_debugobj(iter, "scan /proc/partitions")); - - if (!iter->proc) - iter->proc = fopen(_PATH_PROC_PARTITIONS, "r" UL_CLOEXECSTR); - if (!iter->proc) - return 1; - - while (fgets(buf, sizeof(buf), iter->proc)) { - unsigned int m; - char name[128 + 1]; - - - if (sscanf(buf, " %u %*s %*s %128[^\n ]", - &m, name) != 2 || m != LOOPDEV_MAJOR) - continue; - - DBG(ITER, ul_debugobj(iter, "checking %s", name)); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } - - return 1; -} - -/* - * Set the next *used* loop device according to - * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required). - * - * This is preferred method. - */ -static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter = &lc->iter; - struct dirent *d; - int fd; - - DBG(ITER, ul_debugobj(iter, "scanning /sys/block")); - - if (!iter->sysblock) - iter->sysblock = opendir(_PATH_SYS_BLOCK); - - if (!iter->sysblock) - return 1; - - fd = dirfd(iter->sysblock); - - while ((d = readdir(iter->sysblock))) { - char name[NAME_MAX + 18 + 1]; - struct stat st; - - DBG(ITER, ul_debugobj(iter, "check %s", d->d_name)); - - if (strcmp(d->d_name, ".") == 0 - || strcmp(d->d_name, "..") == 0 - || strncmp(d->d_name, "xloop", 4) != 0) - continue; - - snprintf(name, sizeof(name), "%s/xloop/backing_file", d->d_name); - if (fstatat(fd, name, &st, 0) != 0) - continue; - - if (loopiter_set_device(lc, d->d_name) == 0) - return 0; - } - - return 1; -} - -/* - * @lc: context, has to initialized by loopcxt_init_iterator() - * - * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details - * about the current loop device are available by - * loopcxt_get_{fd,backing_file,device,offset, ...} functions. - */ -int loopcxt_next(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter; - - if (!lc) - return -EINVAL; - - - iter = &lc->iter; - if (iter->done) - return 1; - - DBG(ITER, ul_debugobj(iter, "next")); - - /* A) Look for used loop devices in /proc/partitions ("losetup -a" only) - */ - if (iter->flags & LOOPITER_FL_USED) { - int rc; - - if (loopcxt_sysfs_available(lc)) - rc = loopcxt_next_from_sysfs(lc); - else - rc = loopcxt_next_from_proc(lc); - if (rc == 0) - return 0; - goto done; - } - - /* B) Classic way, try first eight loop devices (default number - * of loop devices). This is enough for 99% of all cases. - */ - if (iter->default_check) { - DBG(ITER, ul_debugobj(iter, "next: default check")); - for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES; - iter->ncur++) { - char name[16]; - snprintf(name, sizeof(name), "xloop%d", iter->ncur); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } - iter->default_check = 0; - } - - /* C) the worst possibility, scan whole /dev or /dev/xloop/ - */ - if (!iter->minors) { - DBG(ITER, ul_debugobj(iter, "next: scanning /dev")); - iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ? - loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) : - loop_scandir(_PATH_DEV, &iter->minors, 1); - iter->ncur = -1; - } - for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) { - char name[16]; - snprintf(name, sizeof(name), "xloop%d", iter->minors[iter->ncur]); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } -done: - loopcxt_deinit_iterator(lc); - return 1; -} - -/* - * @device: path to device - */ -int is_loopdev(const char *device) -{ - struct stat st; - - if (device && stat(device, &st) == 0 && - S_ISBLK(st.st_mode) && - major(st.st_rdev) == LOOPDEV_MAJOR) - return 1; - - errno = ENODEV; - return 0; -} - -/* - * @lc: context - * - * Returns result from LOOP_GET_STAT64 ioctl or NULL on error. - */ -struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc) -{ - int fd; - - if (!lc || lc->info_failed) { - errno = EINVAL; - return NULL; - } - errno = 0; - if (lc->has_info) - return &lc->info; - - fd = loopcxt_get_fd(lc); - if (fd < 0) - return NULL; - - if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) { - lc->has_info = 1; - lc->info_failed = 0; - DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK")); - return &lc->info; - } - - lc->info_failed = 1; - DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED")); - - return NULL; -} - -/* - * @lc: context - * - * Returns (allocated) string with path to the file associated - * with the current loop device. - */ -char *loopcxt_get_backing_file(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - char *res = NULL; - - if (sysfs) - /* - * This is always preferred, the loop_info64 - * has too small buffer for the filename. - */ - ul_path_read_string(sysfs, &res, "xloop/backing_file"); - - if (!res && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - - if (lo) { - lo->lo_file_name[LO_NAME_SIZE - 2] = '*'; - lo->lo_file_name[LO_NAME_SIZE - 1] = '\0'; - res = strdup((char *) lo->lo_file_name); - } - } - - DBG(CXT, ul_debugobj(lc, "get_backing_file [%s]", res)); - return res; -} - -/* - * @lc: context - * @offset: returns offset number for the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = -EINVAL; - - if (sysfs) - rc = ul_path_read_u64(sysfs, offset, "xloop/offset"); - - if (rc && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) { - if (offset) - *offset = lo->lo_offset; - rc = 0; - } else - rc = -errno; - } - - DBG(CXT, ul_debugobj(lc, "get_offset [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @blocksize: returns logical blocksize for the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = -EINVAL; - - if (sysfs) - rc = ul_path_read_u64(sysfs, blocksize, "queue/logical_block_size"); - - /* Fallback based on BLKSSZGET ioctl */ - if (rc) { - int fd = loopcxt_get_fd(lc); - int sz = 0; - - if (fd < 0) - return -EINVAL; - rc = blkdev_get_sector_size(fd, &sz); - if (rc) - return rc; - - *blocksize = sz; - } - - DBG(CXT, ul_debugobj(lc, "get_blocksize [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @sizelimit: returns size limit for the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = -EINVAL; - - if (sysfs) - rc = ul_path_read_u64(sysfs, size, "xloop/sizelimit"); - - if (rc && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) { - if (size) - *size = lo->lo_sizelimit; - rc = 0; - } else - rc = -errno; - } - - DBG(CXT, ul_debugobj(lc, "get_sizelimit [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @devno: returns encryption type - * - * Cryptoloop is DEPRECATED! - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc; - - /* not provided by sysfs */ - if (lo) { - if (type) - *type = lo->lo_encrypt_type; - rc = 0; - } else - rc = -errno; - - DBG(CXT, ul_debugobj(lc, "get_encrypt_type [rc=%d]", rc)); - return rc; -} - -/* - * @file_fmt_type_str: file format type string. - * @file_fmt_type: returns file format type from the given file format string. - * - * Returns: <0 on error, 0 on success - */ -int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type) -{ - int rc = 0; - - if (!strcmp(file_fmt_type_str, "RAW")) - *file_fmt_type = LO_FILE_FMT_RAW; - else if (!strcmp(file_fmt_type_str, "QCOW")) - *file_fmt_type = LO_FILE_FMT_QCOW; - else if (!strcmp(file_fmt_type_str, "VDI")) - *file_fmt_type = LO_FILE_FMT_VDI; - else if (!strcmp(file_fmt_type_str, "VMDK")) - *file_fmt_type = LO_FILE_FMT_VMDK; - else - rc = -EINVAL; - - return rc; -} - -/* - * @lc: context - * @file_fmt_type: returns file format type of the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = 0; - - if (sysfs) { - /* check if file_fmt_type is accessible and supported by the kernel module */ - char* file_fmt_str = NULL; - if (ul_path_read_string(sysfs, &file_fmt_str, "xloop/file_fmt_type") == 0) - rc = parse_file_fmt_type(file_fmt_str, file_fmt_type); - } else - rc = -errno; - - if (rc != 0 && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - *file_fmt_type = lo->lo_file_fmt_type; - } - - return 0; -} - -/* - * @lc: context - * - * Returns (allocated) string with file format type of the current loop device. - */ -char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - char *res = NULL; - - if (sysfs) - ul_path_read_string(sysfs, &res, "xloop/file_fmt_type"); - - DBG(CXT, ul_debugobj(lc, "xloopcxt_get_file_fmt_type_string [%s]", res)); - return res; -} - -/* - * @lc: context - * @devno: returns crypt name - * - * Cryptoloop is DEPRECATED! - * - * Returns: <0 on error, 0 on success - */ -const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - - if (lo) - return (char *) lo->lo_crypt_name; - - DBG(CXT, ul_debugobj(lc, "get_crypt_name failed")); - return NULL; -} - -/* - * @lc: context - * @devno: returns backing file devno - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc; - - if (lo) { - if (devno) - *devno = lo->lo_device; - rc = 0; - } else - rc = -errno; - - DBG(CXT, ul_debugobj(lc, "get_backing_devno [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @ino: returns backing file inode - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc; - - if (lo) { - if (ino) - *ino = lo->lo_inode; - rc = 0; - } else - rc = -errno; - - DBG(CXT, ul_debugobj(lc, "get_backing_inode [rc=%d]", rc)); - return rc; -} - -/* - * Check if the kernel supports partitioned loop devices. - * - * Notes: - * - kernels < 3.2 support partitioned loop devices and PT scanning - * only if max_part= module parameter is non-zero - * - * - kernels >= 3.2 always support partitioned loop devices - * - * - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls - * - * - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the - * LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled - * by default. - * - * See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98. - */ -int loopmod_supports_partscan(void) -{ - int rc, ret = 0; - FILE *f; - - if (get_linux_version() >= KERNEL_VERSION(3,2,0)) - return 1; - - f = fopen("/sys/module/loop/parameters/max_part", "r" UL_CLOEXECSTR); - if (!f) - return 0; - rc = fscanf(f, "%d", &ret); - fclose(f); - return rc == 1 ? ret : 0; -} - -/* - * @lc: context - * - * Returns: 1 if the partscan flags is set *or* (for old kernels) partitions - * scanning is enabled for all loop devices. - */ -int loopcxt_is_partscan(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - /* kernel >= 3.2 */ - int fl; - if (ul_path_read_s32(sysfs, &fl, "xloop/partscan") == 0) - return fl; - } - - /* old kernels (including kernels without loopN/loop/ directory */ - return loopmod_supports_partscan(); -} - -/* - * @lc: context - * - * Returns: 1 if the autoclear flags is set. - */ -int loopcxt_is_autoclear(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - int fl; - if (ul_path_read_s32(sysfs, &fl, "xloop/autoclear") == 0) - return fl; - } - - if (loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - return lo->lo_flags & LO_FLAGS_AUTOCLEAR; - } - return 0; -} - -/* - * @lc: context - * - * Returns: 1 if the readonly flags is set. - */ -int loopcxt_is_readonly(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - int fl; - if (ul_path_read_s32(sysfs, &fl, "ro") == 0) - return fl; - } - - if (loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - return lo->lo_flags & LO_FLAGS_READ_ONLY; - } - return 0; -} - -/* - * @lc: context - * - * Returns: 1 if the dio flags is set. - */ -int loopcxt_is_dio(struct loopdev_cxt *lc) -{ - struct path_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - int fl; - if (ul_path_read_s32(sysfs, &fl, "xloop/dio") == 0) - return fl; - } - if (loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - return lo->lo_flags & LO_FLAGS_DIRECT_IO; - } - return 0; -} - -/* - * @lc: context - * @st: backing file stat or NULL - * @backing_file: filename - * @offset: offset (use LOOPDEV_FL_OFFSET if specified) - * @sizelimit: size limit (use LOOPDEV_FL_SIZELIMIT if specified) - * @flags: LOOPDEV_FL_{OFFSET,SIZELIMIT} - * - * Returns 1 if the current @lc loopdev is associated with the given backing - * file. Note that the preferred way is to use devno and inode number rather - * than filename. The @backing_file filename is poor solution usable in case - * that you don't have rights to call stat(). - * - * LOOPDEV_FL_SIZELIMIT requires LOOPDEV_FL_OFFSET being set as well. - * - * Don't forget that old kernels provide very restricted (in size) backing - * filename by LOOP_GET_STAT64 ioctl only. - */ -int loopcxt_is_used(struct loopdev_cxt *lc, - struct stat *st, - const char *backing_file, - uint64_t offset, - uint64_t sizelimit, - int flags) -{ - ino_t ino = 0; - dev_t dev = 0; - - if (!lc) - return 0; - - DBG(CXT, ul_debugobj(lc, "checking %s vs. %s", - loopcxt_get_device(lc), - backing_file)); - - if (st && loopcxt_get_backing_inode(lc, &ino) == 0 && - loopcxt_get_backing_devno(lc, &dev) == 0) { - - if (ino == st->st_ino && dev == st->st_dev) - goto found; - - /* don't use filename if we have devno and inode */ - return 0; - } - - /* poor man's solution */ - if (backing_file) { - char *name = loopcxt_get_backing_file(lc); - int rc = name && strcmp(name, backing_file) == 0; - - free(name); - if (rc) - goto found; - } - - return 0; -found: - if (flags & LOOPDEV_FL_OFFSET) { - uint64_t off = 0; - - int rc = loopcxt_get_offset(lc, &off) == 0 && off == offset; - - if (rc && flags & LOOPDEV_FL_SIZELIMIT) { - uint64_t sz = 0; - - return loopcxt_get_sizelimit(lc, &sz) == 0 && sz == sizelimit; - } - return rc; - } - return 1; -} - -/* - * The setting is removed by loopcxt_set_device() loopcxt_next()! - */ -int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset) -{ - if (!lc) - return -EINVAL; - lc->info.lo_offset = offset; - - DBG(CXT, ul_debugobj(lc, "set offset=%jd", offset)); - return 0; -} - -/* - * The setting is removed by loopcxt_set_device() loopcxt_next()! - */ -int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit) -{ - if (!lc) - return -EINVAL; - lc->info.lo_sizelimit = sizelimit; - - DBG(CXT, ul_debugobj(lc, "set sizelimit=%jd", sizelimit)); - return 0; -} - -/* - * The blocksize will be used by loopcxt_set_device(). For already exiting - * devices use loopcxt_ioctl_blocksize(). - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - */ -int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) -{ - if (!lc) - return -EINVAL; - lc->blocksize = blocksize; - - DBG(CXT, ul_debugobj(lc, "set blocksize=%jd", blocksize)); - return 0; -} - -/* - * @lc: context - * @file_fmt_type: kernel LO_FILE_FMT_{RAW,QCOW,VDI,VMDK} flags - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - * - * Returns: 0 on success, <0 on error. - */ -int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type) { - if (!lc) - return -EINVAL; - lc->info.lo_file_fmt_type = file_fmt_type; - - DBG(CXT, ul_debugobj(lc, "set file_fmt_type=%u", (unsigned) file_fmt_type)); - return 0; -} - -/* - * @lc: context - * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - * - * Returns: 0 on success, <0 on error. - */ -int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags) -{ - if (!lc) - return -EINVAL; - lc->info.lo_flags = flags; - - DBG(CXT, ul_debugobj(lc, "set flags=%u", (unsigned) flags)); - return 0; -} - -/* - * @lc: context - * @filename: backing file path (the path will be canonicalized) - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - * - * Returns: 0 on success, <0 on error. - */ -int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename) -{ - if (!lc) - return -EINVAL; - - lc->filename = canonicalize_path(filename); - if (!lc->filename) - return -errno; - - xstrncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE); - - DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->info.lo_file_name)); - return 0; -} - -/* - * In kernels prior to v3.9, if the offset or sizelimit options - * are used, the block device's size won't be synced automatically. - * blockdev --getsize64 and filesystems will use the backing - * file size until the block device has been re-opened or the - * LOOP_SET_CAPACITY ioctl is called to sync the sizes. - * - * Since mount -oloop uses the LO_FLAGS_AUTOCLEAR option and passes - * the open file descriptor to the mount system call, we need to use - * the ioctl. Calling losetup directly doesn't have this problem since - * it closes the device when it exits and whatever consumes the device - * next will re-open it, causing the resync. - */ -static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd) -{ - uint64_t size, expected_size; - int dev_fd; - struct stat st; - - if (!lc->info.lo_offset && !lc->info.lo_sizelimit) - return 0; - - if (fstat(file_fd, &st)) { - DBG(CXT, ul_debugobj(lc, "failed to fstat backing file")); - return -errno; - } - if (S_ISBLK(st.st_mode)) { - if (blkdev_get_size(file_fd, - (unsigned long long *) &expected_size)) { - DBG(CXT, ul_debugobj(lc, "failed to determine device size")); - return -errno; - } - } else - expected_size = st.st_size; - - if (expected_size == 0 || expected_size <= lc->info.lo_offset) { - DBG(CXT, ul_debugobj(lc, "failed to determine expected size")); - return 0; /* ignore this error */ - } - - if (lc->info.lo_offset > 0) - expected_size -= lc->info.lo_offset; - - if (lc->info.lo_sizelimit > 0 && lc->info.lo_sizelimit < expected_size) - expected_size = lc->info.lo_sizelimit; - - dev_fd = loopcxt_get_fd(lc); - if (dev_fd < 0) { - DBG(CXT, ul_debugobj(lc, "failed to get loop FD")); - return -errno; - } - - if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) { - DBG(CXT, ul_debugobj(lc, "failed to determine loopdev size")); - return -errno; - } - - /* It's block device, so, align to 512-byte sectors */ - if (expected_size % 512) { - DBG(CXT, ul_debugobj(lc, "expected size misaligned to 512-byte sectors")); - expected_size = (expected_size >> 9) << 9; - } - - if (expected_size != size) { - DBG(CXT, ul_debugobj(lc, "warning: loopdev and expected " - "size mismatch (%ju/%ju)", - size, expected_size)); - - if (loopcxt_ioctl_capacity(lc)) { - /* ioctl not available */ - if (errno == ENOTTY || errno == EINVAL) - errno = ERANGE; - return -errno; - } - - if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) - return -errno; - - if (expected_size != size) { - errno = ERANGE; - DBG(CXT, ul_debugobj(lc, "failed to set loopdev size, " - "size: %ju, expected: %ju", - size, expected_size)); - return -errno; - } - } - - return 0; -} - -/* - * @lc: context - * - * Associate the current device (see loopcxt_{set,get}_device()) with - * a file (see loopcxt_set_backing_file()). - * - * The device is initialized read-write by default. If you want read-only - * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_* - * flags are ignored and modified according to LO_FLAGS_*. - * - * If the device is already open by loopcxt_get_fd() then this setup device - * function will re-open the device to fix read/write mode. - * - * The device is also initialized read-only if the backing file is not - * possible to open read-write (e.g. read-only FS). - * - * Returns: <0 on error, 0 on success. - */ -int loopcxt_setup_device(struct loopdev_cxt *lc) -{ - int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0, err, again; - int errsv = 0; - - if (!lc || !*lc->device || !lc->filename) - return -EINVAL; - - DBG(SETUP, ul_debugobj(lc, "device setup requested")); - - /* - * Open backing file and device - */ - if (lc->info.lo_flags & LO_FLAGS_READ_ONLY) - mode = O_RDONLY; - - if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) { - if (mode != O_RDONLY && (errno == EROFS || errno == EACCES)) - file_fd = open(lc->filename, mode = O_RDONLY); - - if (file_fd < 0) { - DBG(SETUP, ul_debugobj(lc, "open backing file failed: %m")); - return -errno; - } - } - DBG(SETUP, ul_debugobj(lc, "backing file open: OK")); - - if (lc->fd != -1 && lc->mode != mode) { - DBG(SETUP, ul_debugobj(lc, "closing already open device (mode mismatch)")); - close(lc->fd); - lc->fd = -1; - lc->mode = 0; - } - - if (mode == O_RDONLY) { - lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */ - lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */ - } else { - lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */ - lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY; - lc->flags &= ~LOOPDEV_FL_RDONLY; - } - - do { - errno = 0; - dev_fd = loopcxt_get_fd(lc); - if (dev_fd >= 0 || lc->control_ok == 0) - break; - if (errno != EACCES && errno != ENOENT) - break; - /* We have permissions to open /dev/xloop-control, but open - * /dev/xloopN failed with EACCES, it's probably because udevd - * does not applied chown yet. Let's wait a moment. */ - xusleep(25000); - } while (cnt++ < 16); - - if (dev_fd < 0) { - rc = -errno; - goto err; - } - - DBG(SETUP, ul_debugobj(lc, "device open: OK")); - - /* - * Set FD - */ - if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { - rc = -errno; - errsv = errno; - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m")); - goto err; - } - - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK")); - - if (lc->blocksize > 0 - && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) { - errsv = -rc; - goto err; - } - - do { - err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info); - again = err && errno == EAGAIN; - if (again) - xusleep(250000); - } while (again); - if (err) { - rc = -errno; - errsv = errno; - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); - goto err; - } - - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK")); - - if ((rc = loopcxt_check_size(lc, file_fd))) - goto err; - - close(file_fd); - - memset(&lc->info, 0, sizeof(lc->info)); - lc->has_info = 0; - lc->info_failed = 0; - - DBG(SETUP, ul_debugobj(lc, "success [rc=0]")); - return 0; -err: - if (file_fd >= 0) - close(file_fd); - if (dev_fd >= 0 && rc != -EBUSY) - ioctl(dev_fd, LOOP_CLR_FD, 0); - if (errsv) - errno = errsv; - - DBG(SETUP, ul_debugobj(lc, "failed [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * - * Update status of the current device (see loopcxt_{set,get}_device()). - * - * Note that once initialized, kernel accepts only selected changes: - * LO_FLAGS_AUTOCLEAR and LO_FLAGS_PARTSCAN - * For more see linux/drivers/block/loop.c:loop_set_status() - * - * Returns: <0 on error, 0 on success. - */ -int loopcxt_ioctl_status(struct loopdev_cxt *lc) -{ - int dev_fd, rc = -1, err, again; - - errno = 0; - dev_fd = loopcxt_get_fd(lc); - - if (dev_fd < 0) { - rc = -errno; - return rc; - } - DBG(SETUP, ul_debugobj(lc, "device open: OK")); - - do { - err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info); - again = err && errno == EAGAIN; - if (again) - xusleep(250000); - } while (again); - if (err) { - rc = -errno; - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); - return rc; - } - - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK")); - return 0; -} - -int loopcxt_ioctl_capacity(struct loopdev_cxt *lc) -{ - int fd = loopcxt_get_fd(lc); - - if (fd < 0) - return -EINVAL; - - /* Kernels prior to v2.6.30 don't support this ioctl */ - if (ioctl(fd, LOOP_SET_CAPACITY, 0) < 0) { - int rc = -errno; - DBG(CXT, ul_debugobj(lc, "LOOP_SET_CAPACITY failed: %m")); - return rc; - } - - DBG(CXT, ul_debugobj(lc, "capacity set")); - return 0; -} - -int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio) -{ - int fd = loopcxt_get_fd(lc); - - if (fd < 0) - return -EINVAL; - - /* Kernels prior to v4.4 don't support this ioctl */ - if (ioctl(fd, LOOP_SET_DIRECT_IO, use_dio) < 0) { - int rc = -errno; - DBG(CXT, ul_debugobj(lc, "LOOP_SET_DIRECT_IO failed: %m")); - return rc; - } - - DBG(CXT, ul_debugobj(lc, "direct io set")); - return 0; -} - -/* - * Kernel uses "unsigned long" as ioctl arg, but we use u64 for all sizes to - * keep loopdev internal API simple. - */ -int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) -{ - int fd = loopcxt_get_fd(lc); - - if (fd < 0) - return -EINVAL; - - /* Kernels prior to v4.14 don't support this ioctl */ - if (ioctl(fd, LOOP_SET_BLOCK_SIZE, (unsigned long) blocksize) < 0) { - int rc = -errno; - DBG(CXT, ul_debugobj(lc, "LOOP_SET_BLOCK_SIZE failed: %m")); - return rc; - } - - DBG(CXT, ul_debugobj(lc, "logical block size set")); - return 0; -} - -int loopcxt_delete_device(struct loopdev_cxt *lc) -{ - int fd = loopcxt_get_fd(lc); - - if (fd < 0) - return -EINVAL; - - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m")); - return -errno; - } - - DBG(CXT, ul_debugobj(lc, "device removed")); - return 0; -} - -int loopcxt_add_device(struct loopdev_cxt *lc) -{ - int rc = -EINVAL; - int ctl, nr = -1; - const char *p, *dev = loopcxt_get_device(lc); - - if (!dev) - goto done; - - if (!(lc->flags & LOOPDEV_FL_CONTROL)) { - rc = -ENOSYS; - goto done; - } - - p = strrchr(dev, '/'); - if (!p || (sscanf(p, "/xloop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1) - || nr < 0) - goto done; - - ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); - if (ctl >= 0) { - DBG(CXT, ul_debugobj(lc, "add_device %d", nr)); - rc = ioctl(ctl, LOOP_CTL_ADD, nr); - close(ctl); - } - lc->control_ok = rc >= 0 ? 1 : 0; -done: - DBG(CXT, ul_debugobj(lc, "add_device done [rc=%d]", rc)); - return rc; -} - -/* - * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older - * kernels we have to check all loop devices to found unused one. - * - * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484. - */ -int loopcxt_find_unused(struct loopdev_cxt *lc) -{ - int rc = -1; - - DBG(CXT, ul_debugobj(lc, "find_unused requested")); - - if (lc->flags & LOOPDEV_FL_CONTROL) { - int ctl; - - DBG(CXT, ul_debugobj(lc, "using xloop-control")); - - ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); - if (ctl >= 0) - rc = ioctl(ctl, LOOP_CTL_GET_FREE); - if (rc >= 0) { - char name[16]; - snprintf(name, sizeof(name), "xloop%d", rc); - - rc = loopiter_set_device(lc, name); - } - lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0; - if (ctl >= 0) - close(ctl); - DBG(CXT, ul_debugobj(lc, "find_unused by xloop-control [rc=%d]", rc)); - } - - if (rc < 0) { - DBG(CXT, ul_debugobj(lc, "using loop scan")); - rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE); - if (rc) - return rc; - - rc = loopcxt_next(lc); - loopcxt_deinit_iterator(lc); - DBG(CXT, ul_debugobj(lc, "find_unused by scan [rc=%d]", rc)); - } - return rc; -} - - - -/* - * Return: TRUE/FALSE - */ -int loopdev_is_autoclear(const char *device) -{ - struct loopdev_cxt lc; - int rc; - - if (!device) - return 0; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (!rc) - rc = loopcxt_is_autoclear(&lc); - - loopcxt_deinit(&lc); - return rc; -} - -char *loopdev_get_backing_file(const char *device) -{ - struct loopdev_cxt lc; - char *res = NULL; - - if (!device) - return NULL; - if (loopcxt_init(&lc, 0)) - return NULL; - if (loopcxt_set_device(&lc, device) == 0) - res = loopcxt_get_backing_file(&lc); - - loopcxt_deinit(&lc); - return res; -} - -/* - * Returns: TRUE/FALSE - */ -int loopdev_is_used(const char *device, const char *filename, - uint64_t offset, uint64_t sizelimit, int flags) -{ - struct loopdev_cxt lc; - struct stat st; - int rc = 0; - - if (!device || !filename) - return 0; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (rc) - return rc; - - rc = !stat(filename, &st); - rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, sizelimit, flags); - - loopcxt_deinit(&lc); - return rc; -} - -int loopdev_delete(const char *device) -{ - struct loopdev_cxt lc; - int rc; - - if (!device) - return -EINVAL; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (!rc) - rc = loopcxt_delete_device(&lc); - loopcxt_deinit(&lc); - return rc; -} - -/* - * Returns: 0 = success, < 0 error, 1 not found - */ -int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, - uint64_t offset, uint64_t sizelimit, int flags) -{ - int rc, hasst; - struct stat st; - - if (!filename) - return -EINVAL; - - hasst = !stat(filename, &st); - - rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); - if (rc) - return rc; - - while ((rc = loopcxt_next(lc)) == 0) { - - if (loopcxt_is_used(lc, hasst ? &st : NULL, - filename, offset, sizelimit, flags)) - break; - } - - loopcxt_deinit_iterator(lc); - return rc; -} - -/* - * Returns: 0 = not found, < 0 error, 1 found, 2 found full size and offset match - */ -int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename, - uint64_t offset, uint64_t sizelimit) -{ - int rc, hasst; - struct stat st; - - if (!filename) - return -EINVAL; - - DBG(CXT, ul_debugobj(lc, "find_overlap requested")); - hasst = !stat(filename, &st); - - rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); - if (rc) - return rc; - - while ((rc = loopcxt_next(lc)) == 0) { - uint64_t lc_sizelimit, lc_offset; - - rc = loopcxt_is_used(lc, hasst ? &st : NULL, - filename, offset, sizelimit, 0); - if (!rc) - continue; /* unused */ - if (rc < 0) - break; /* error */ - - DBG(CXT, ul_debugobj(lc, "found %s backed by %s", - loopcxt_get_device(lc), filename)); - - rc = loopcxt_get_offset(lc, &lc_offset); - if (rc) { - DBG(CXT, ul_debugobj(lc, "failed to get offset for device %s", - loopcxt_get_device(lc))); - break; - } - rc = loopcxt_get_sizelimit(lc, &lc_sizelimit); - if (rc) { - DBG(CXT, ul_debugobj(lc, "failed to get sizelimit for device %s", - loopcxt_get_device(lc))); - break; - } - - /* full match */ - if (lc_sizelimit == sizelimit && lc_offset == offset) { - DBG(CXT, ul_debugobj(lc, "overlapping loop device %s (full match)", - loopcxt_get_device(lc))); - rc = 2; - goto found; - } - - /* overlap */ - if (lc_sizelimit != 0 && offset >= lc_offset + lc_sizelimit) - continue; - if (sizelimit != 0 && offset + sizelimit <= lc_offset) - continue; - - DBG(CXT, ul_debugobj(lc, "overlapping loop device %s", - loopcxt_get_device(lc))); - rc = 1; - goto found; - } - - if (rc == 1) - rc = 0; /* not found */ -found: - loopcxt_deinit_iterator(lc); - DBG(CXT, ul_debugobj(lc, "find_overlap done [rc=%d]", rc)); - return rc; -} - -/* - * Returns allocated string with device name - */ -char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, uint64_t sizelimit, int flags) -{ - struct loopdev_cxt lc; - char *res = NULL; - - if (!filename) - return NULL; - - if (loopcxt_init(&lc, 0)) - return NULL; - if (loopcxt_find_by_backing_file(&lc, filename, offset, sizelimit, flags) == 0) - res = loopcxt_strdup_device(&lc); - loopcxt_deinit(&lc); - - return res; -} - -/* - * Returns number of loop devices associated with @file, if only one loop - * device is associated with the given @filename and @loopdev is not NULL then - * @loopdev returns name of the device. - */ -int loopdev_count_by_backing_file(const char *filename, char **loopdev) -{ - struct loopdev_cxt lc; - int count = 0, rc; - - if (!filename) - return -1; - - rc = loopcxt_init(&lc, 0); - if (rc) - return rc; - if (loopcxt_init_iterator(&lc, LOOPITER_FL_USED)) - return -1; - - while(loopcxt_next(&lc) == 0) { - char *backing = loopcxt_get_backing_file(&lc); - - if (!backing || strcmp(backing, filename) != 0) { - free(backing); - continue; - } - - free(backing); - if (loopdev && count == 0) - *loopdev = loopcxt_strdup_device(&lc); - count++; - } - - loopcxt_deinit(&lc); - - if (loopdev && count > 1) { - free(*loopdev); - *loopdev = NULL; - } - return count; -} - diff --git a/utils/lib/mangle.c b/utils/lib/mangle.c deleted file mode 100644 index 1a3b89a..0000000 --- a/utils/lib/mangle.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Functions for \oct encoding used in mtab/fstab/swaps/etc. - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Copyright (C) 2010 Karel Zak - */ -#include -#include -#include -#include - -#include "mangle.h" -#include "c.h" - -#define isoctal(a) (((a) & ~7) == '0') - -#define from_hex(c) (isdigit(c) ? c - '0' : tolower(c) - 'a' + 10) - -#define is_unwanted_char(x) (strchr(" \t\n\\", (unsigned int) x) != NULL) - - -char *mangle(const char *s) -{ - char *ss, *sp; - - if (!s) - return NULL; - - ss = sp = malloc(4 * strlen(s) + 1); - if (!sp) - return NULL; - while(1) { - if (!*s) { - *sp = '\0'; - break; - } - if (is_unwanted_char(*s)) { - *sp++ = '\\'; - *sp++ = '0' + ((*s & 0300) >> 6); - *sp++ = '0' + ((*s & 070) >> 3); - *sp++ = '0' + (*s & 07); - } else - *sp++ = *s; - s++; - } - return ss; -} - - -void unmangle_to_buffer(const char *s, char *buf, size_t len) -{ - size_t sz = 0; - - if (!s) - return; - - while(*s && sz < len - 1) { - if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) && - isoctal(s[2]) && isoctal(s[3])) { - - *buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7); - s += 4; - sz += 4; - } else { - *buf++ = *s++; - sz++; - } - } - *buf = '\0'; -} - -size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len) -{ - size_t sz = 0; - const char *buf0 = buf; - - if (!s) - return 0; - - while(*s && sz < len - 1) { - if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' && - isxdigit(s[2]) && isxdigit(s[3])) { - - *buf++ = from_hex(s[2]) << 4 | from_hex(s[3]); - s += 4; - sz += 4; - } else { - *buf++ = *s++; - sz++; - } - } - *buf = '\0'; - return buf - buf0 + 1; -} - -static inline const char *skip_nonspaces(const char *s) -{ - while (s && *s && !(*s == ' ' || *s == '\t')) - s++; - return s; -} - -/* - * Returns mallocated buffer or NULL in case of error. - */ -char *unmangle(const char *s, const char **end) -{ - char *buf; - const char *e; - size_t sz; - - if (!s) - return NULL; - - e = skip_nonspaces(s); - sz = e - s + 1; - - if (end) - *end = e; - if (e == s) - return NULL; /* empty string */ - - buf = malloc(sz); - if (!buf) - return NULL; - - unmangle_to_buffer(s, buf, sz); - return buf; -} - -#ifdef TEST_PROGRAM_MANGLE -#include -int main(int argc, char *argv[]) -{ - char *p = NULL; - if (argc < 3) { - fprintf(stderr, "usage: %s --mangle|unmangle \n", - program_invocation_short_name); - return EXIT_FAILURE; - } - - if (!strcmp(argv[1], "--mangle")) { - p = mangle(argv[2]); - printf("mangled: '%s'\n", p); - free(p); - } - - else if (!strcmp(argv[1], "--unmangle")) { - char *x = unmangle(argv[2], NULL); - - if (x) { - printf("unmangled: '%s'\n", x); - free(x); - } - - x = strdup(argv[2]); - if (x) { - unmangle_to_buffer(x, x, strlen(x) + 1); - - printf("self-unmangled: '%s'\n", x); - free(x); - } - } - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_MANGLE */ diff --git a/utils/lib/match.c b/utils/lib/match.c deleted file mode 100644 index a286a19..0000000 --- a/utils/lib/match.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2011 Karel Zak - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include - -#include "match.h" - -/* - * match_fstype: - * @type: filesystem type - * @pattern: filesystem name or comma delimited list of names - * - * The @pattern list of filesystem can be prefixed with a global - * "no" prefix to invert matching of the whole list. The "no" could - * also be used for individual items in the @pattern list. So, - * "nofoo,bar" has the same meaning as "nofoo,nobar". - */ -int match_fstype(const char *type, const char *pattern) -{ - int no = 0; /* negated types list */ - int len; - const char *p; - - if (!pattern && !type) - return 1; - if (!pattern) - return 0; - - if (!strncmp(pattern, "no", 2)) { - no = 1; - pattern += 2; - } - - /* Does type occur in types, separated by commas? */ - len = strlen(type); - p = pattern; - while(1) { - if (!strncmp(p, "no", 2) && !strncasecmp(p+2, type, len) && - (p[len+2] == 0 || p[len+2] == ',')) - return 0; - if (strncasecmp(p, type, len) == 0 && (p[len] == 0 || p[len] == ',')) - return !no; - p = strchr(p,','); - if (!p) - break; - p++; - } - return no; -} diff --git a/utils/lib/mbsalign.c b/utils/lib/mbsalign.c deleted file mode 100644 index e251202..0000000 --- a/utils/lib/mbsalign.c +++ /dev/null @@ -1,627 +0,0 @@ -/* Align/Truncate a string in a given screen width - Copyright (C) 2009-2010 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 2.1 of the License, or - (at your option) any later version. - - This program 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* Written by Pádraig Brady. */ - -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "mbsalign.h" -#include "strutils.h" -#include "widechar.h" - -/* - * Counts number of cells in multibyte string. All control and - * non-printable chars are ignored. - * - * Returns: number of cells. - */ -size_t mbs_nwidth(const char *buf, size_t bufsz) -{ - const char *p = buf, *last = buf; - size_t width = 0; - -#ifdef HAVE_WIDECHAR - mbstate_t st; - memset(&st, 0, sizeof(st)); -#endif - if (p && *p && bufsz) - last = p + (bufsz - 1); - - while (p && *p && p <= last) { - if (iscntrl((unsigned char) *p)) { - p++; - - /* try detect "\e[x;ym" and skip on success */ - if (*p && *p == '[') { - const char *e = p; - while (*e && e < last && *e != 'm') - e++; - if (*e == 'm') - p = e + 1; - } - continue; - } -#ifdef HAVE_WIDECHAR - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); - - if (len == 0) - break; - if (len > 0 && iswprint(wc)) { - int x = wcwidth(wc); - if (x > 0) - width += x; - } else if (len == (size_t) -1 || len == (size_t) -2) - len = 1; - p += len; -#else - if (isprint((unsigned char) *p)) - width++; - p++; -#endif - } - - return width; -} - -size_t mbs_width(const char *s) -{ - if (!s || !*s) - return 0; - return mbs_nwidth(s, strlen(s)); -} - -/* - * Counts number of cells in multibyte string. For all control and - * non-printable chars is the result width enlarged to store \x?? hex - * sequence. See mbs_safe_encode(). - * - * Returns: number of cells, @sz returns number of bytes. - */ -size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz) -{ - const char *p = buf, *last = buf; - size_t width = 0, bytes = 0; - -#ifdef HAVE_WIDECHAR - mbstate_t st; - memset(&st, 0, sizeof(st)); -#endif - if (p && *p && bufsz) - last = p + (bufsz - 1); - - while (p && *p && p <= last) { - if ((p < last && *p == '\\' && *(p + 1) == 'x') - || iscntrl((unsigned char) *p)) { - width += 4, bytes += 4; /* *p encoded to \x?? */ - p++; - } -#ifdef HAVE_WIDECHAR - else { - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); - - if (len == 0) - break; - - if (len == (size_t) -1 || len == (size_t) -2) { - len = 1; - if (isprint((unsigned char) *p)) - width += 1, bytes += 1; - else - width += 4, bytes += 4; - - } else if (!iswprint(wc)) { - width += len * 4; /* hex encode whole sequence */ - bytes += len * 4; - } else { - width += wcwidth(wc); /* number of cells */ - bytes += len; /* number of bytes */ - } - p += len; - } -#else - else if (!isprint((unsigned char) *p)) { - width += 4, bytes += 4; /* *p encoded to \x?? */ - p++; - } else { - width++, bytes++; - p++; - } -#endif - } - - if (sz) - *sz = bytes; - return width; -} - -size_t mbs_safe_width(const char *s) -{ - if (!s || !*s) - return 0; - return mbs_safe_nwidth(s, strlen(s), NULL); -} - -/* - * Copy @s to @buf and replace control and non-printable chars with - * \x?? hex sequence. The @width returns number of cells. The @safechars - * are not encoded. - * - * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s))) - * bytes. - */ -char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf, const char *safechars) -{ - const char *p = s; - char *r; - size_t sz = s ? strlen(s) : 0; - -#ifdef HAVE_WIDECHAR - mbstate_t st; - memset(&st, 0, sizeof(st)); -#endif - if (!sz || !buf) - return NULL; - - r = buf; - *width = 0; - - while (p && *p) { - if (safechars && strchr(safechars, *p)) { - *r++ = *p++; - continue; - } - - if ((*p == '\\' && *(p + 1) == 'x') - || iscntrl((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - p++; - } -#ifdef HAVE_WIDECHAR - else { - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); - - if (len == 0) - break; /* end of string */ - - if (len == (size_t) -1 || len == (size_t) -2) { - len = 1; - /* - * Not valid multibyte sequence -- maybe it's - * printable char according to the current locales. - */ - if (!isprint((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - } else { - (*width)++; - *r++ = *p; - } - } else if (!iswprint(wc)) { - size_t i; - for (i = 0; i < len; i++) { - sprintf(r, "\\x%02x", (unsigned char) p[i]); - r += 4; - *width += 4; - } - } else { - memcpy(r, p, len); - r += len; - *width += wcwidth(wc); - } - p += len; - } -#else - else if (!isprint((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - p++; - r += 4; - *width += 4; - } else { - *r++ = *p++; - (*width)++; - } -#endif - } - - *r = '\0'; - return buf; -} - -/* - * Copy @s to @buf and replace broken sequences to \x?? hex sequence. The - * @width returns number of cells. The @safechars are not encoded. - * - * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s))) - * bytes. - */ -char *mbs_invalid_encode_to_buffer(const char *s, size_t *width, char *buf) -{ - const char *p = s; - char *r; - size_t sz = s ? strlen(s) : 0; - -#ifdef HAVE_WIDECHAR - mbstate_t st; - memset(&st, 0, sizeof(st)); -#endif - if (!sz || !buf) - return NULL; - - r = buf; - *width = 0; - - while (p && *p) { -#ifdef HAVE_WIDECHAR - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); -#else - size_t len = 1; -#endif - - if (len == 0) - break; /* end of string */ - - if (len == (size_t) -1 || len == (size_t) -2) { - len = 1; - /* - * Not valid multibyte sequence -- maybe it's - * printable char according to the current locales. - */ - if (!isprint((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - } else { - (*width)++; - *r++ = *p; - } - } else if (*p == '\\' && *(p + 1) == 'x') { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - } else { - memcpy(r, p, len); - r += len; - *width += wcwidth(wc); - } - p += len; - } - - *r = '\0'; - return buf; -} - -size_t mbs_safe_encode_size(size_t bytes) -{ - return (bytes * 4) + 1; -} - -/* - * Returns allocated string where all control and non-printable chars are - * replaced with \x?? hex sequence. - */ -char *mbs_safe_encode(const char *s, size_t *width) -{ - size_t sz = s ? strlen(s) : 0; - char *buf, *ret = NULL; - - if (!sz) - return NULL; - buf = malloc(mbs_safe_encode_size(sz)); - if (buf) - ret = mbs_safe_encode_to_buffer(s, width, buf, NULL); - if (!ret) - free(buf); - return ret; -} - -/* - * Returns allocated string where all broken widechars chars are - * replaced with \x?? hex sequence. - */ -char *mbs_invalid_encode(const char *s, size_t *width) -{ - size_t sz = s ? strlen(s) : 0; - char *buf, *ret = NULL; - - if (!sz) - return NULL; - buf = malloc(mbs_safe_encode_size(sz)); - if (buf) - ret = mbs_invalid_encode_to_buffer(s, width, buf); - if (!ret) - free(buf); - return ret; -} - -#ifdef HAVE_WIDECHAR - -static bool -wc_ensure_printable (wchar_t *wchars) -{ - bool replaced = false; - wchar_t *wc = wchars; - while (*wc) - { - if (!iswprint ((wint_t) *wc)) - { - *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ - replaced = true; - } - wc++; - } - return replaced; -} - -/* Truncate wchar string to width cells. - * Returns number of cells used. */ - -static size_t -wc_truncate (wchar_t *wc, size_t width) -{ - size_t cells = 0; - int next_cells = 0; - - while (*wc) - { - next_cells = wcwidth (*wc); - if (next_cells == -1) /* non printable */ - { - *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ - next_cells = 1; - } - if (cells + next_cells > width) - break; - - cells += next_cells; - wc++; - } - *wc = L'\0'; - return cells; -} - -static int -rpl_wcswidth (const wchar_t *s, size_t n) -{ - int ret = 0; - - while (n-- > 0 && *s != L'\0') - { - int nwidth = wcwidth (*s++); - if (nwidth == -1) /* non printable */ - return -1; - if (ret > (INT_MAX - nwidth)) /* overflow */ - return -1; - ret += nwidth; - } - - return ret; -} -#endif /* HAVE_WIDECHAR */ - -/* Truncate multi-byte string to @width and returns number of - * bytes of the new string @str, and in @width returns number - * of cells. - */ -size_t -mbs_truncate(char *str, size_t *width) -{ - ssize_t bytes = strlen(str); -#ifdef HAVE_WIDECHAR - ssize_t sz = mbstowcs(NULL, str, 0); - wchar_t *wcs = NULL; - - if (sz == (ssize_t) -1) - goto done; - - wcs = calloc(1, (sz + 1) * sizeof(wchar_t)); - if (!wcs) - goto done; - - if (!mbstowcs(wcs, str, sz)) - goto done; - *width = wc_truncate(wcs, *width); - bytes = wcstombs(str, wcs, bytes); -done: - free(wcs); -#else - if (bytes >= 0 && *width < (size_t) bytes) - bytes = *width; -#endif - if (bytes >= 0) - str[bytes] = '\0'; - return bytes; -} - -/* Write N_SPACES space characters to DEST while ensuring - nothing is written beyond DEST_END. A terminating NUL - is always added to DEST. - A pointer to the terminating NUL is returned. */ - -static char* -mbs_align_pad (char *dest, const char* dest_end, size_t n_spaces, int padchar) -{ - for (/* nothing */; n_spaces && (dest < dest_end); n_spaces--) - *dest++ = padchar; - *dest = '\0'; - return dest; -} - -size_t -mbsalign (const char *src, char *dest, size_t dest_size, - size_t *width, mbs_align_t align, int flags) -{ - return mbsalign_with_padding(src, dest, dest_size, width, align, flags, ' '); -} - -/* Align a string, SRC, in a field of *WIDTH columns, handling multi-byte - characters; write the result into the DEST_SIZE-byte buffer, DEST. - ALIGNMENT specifies whether to left- or right-justify or to center. - If SRC requires more than *WIDTH columns, truncate it to fit. - When centering, the number of trailing spaces may be one less than the - number of leading spaces. The FLAGS parameter is unused at present. - Return the length in bytes required for the final result, not counting - the trailing NUL. A return value of DEST_SIZE or larger means there - wasn't enough space. DEST will be NUL terminated in any case. - Return (size_t) -1 upon error (invalid multi-byte sequence in SRC, - or malloc failure), unless MBA_UNIBYTE_FALLBACK is specified. - Update *WIDTH to indicate how many columns were used before padding. */ - -size_t -mbsalign_with_padding (const char *src, char *dest, size_t dest_size, - size_t *width, mbs_align_t align, -#ifdef HAVE_WIDECHAR - int flags, -#else - int flags __attribute__((__unused__)), -#endif - int padchar) -{ - size_t ret = -1; - size_t src_size = strlen (src) + 1; - char *newstr = NULL; - wchar_t *str_wc = NULL; - const char *str_to_print = src; - size_t n_cols = src_size - 1; - size_t n_used_bytes = n_cols; /* Not including NUL */ - size_t n_spaces = 0, space_left; - -#ifdef HAVE_WIDECHAR - bool conversion = false; - bool wc_enabled = false; - - /* In multi-byte locales convert to wide characters - to allow easy truncation. Also determine number - of screen columns used. */ - if (MB_CUR_MAX > 1) - { - size_t src_chars = mbstowcs (NULL, src, 0); - if (src_chars == (size_t) -1) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - src_chars += 1; /* make space for NUL */ - str_wc = malloc (src_chars * sizeof (wchar_t)); - if (str_wc == NULL) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - if (mbstowcs (str_wc, src, src_chars) != 0) - { - str_wc[src_chars - 1] = L'\0'; - wc_enabled = true; - conversion = wc_ensure_printable (str_wc); - n_cols = rpl_wcswidth (str_wc, src_chars); - } - } - - /* If we transformed or need to truncate the source string - then create a modified copy of it. */ - if (wc_enabled && (conversion || (n_cols > *width))) - { - if (conversion) - { - /* May have increased the size by converting - \t to \uFFFD for example. */ - src_size = wcstombs(NULL, str_wc, 0) + 1; - } - newstr = malloc (src_size); - if (newstr == NULL) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - str_to_print = newstr; - n_cols = wc_truncate (str_wc, *width); - n_used_bytes = wcstombs (newstr, str_wc, src_size); - } - -mbsalign_unibyte: -#endif - - if (n_cols > *width) /* Unibyte truncation required. */ - { - n_cols = *width; - n_used_bytes = n_cols; - } - - if (*width > n_cols) /* Padding required. */ - n_spaces = *width - n_cols; - - /* indicate to caller how many cells needed (not including padding). */ - *width = n_cols; - - /* indicate to caller how many bytes needed (not including NUL). */ - ret = n_used_bytes + (n_spaces * 1); - - /* Write as much NUL terminated output to DEST as possible. */ - if (dest_size != 0) - { - char *dest_end = dest + dest_size - 1; - size_t start_spaces; - size_t end_spaces; - - switch (align) - { - case MBS_ALIGN_CENTER: - start_spaces = n_spaces / 2 + n_spaces % 2; - end_spaces = n_spaces / 2; - break; - case MBS_ALIGN_LEFT: - start_spaces = 0; - end_spaces = n_spaces; - break; - case MBS_ALIGN_RIGHT: - start_spaces = n_spaces; - end_spaces = 0; - break; - default: - abort(); - } - - dest = mbs_align_pad (dest, dest_end, start_spaces, padchar); - space_left = dest_end - dest; - dest = mempcpy (dest, str_to_print, min (n_used_bytes, space_left)); - mbs_align_pad (dest, dest_end, end_spaces, padchar); - } -#ifdef HAVE_WIDECHAR -mbsalign_cleanup: -#endif - free (str_wc); - free (newstr); - - return ret; -} diff --git a/utils/lib/mbsedit.c b/utils/lib/mbsedit.c deleted file mode 100644 index 8ce5901..0000000 --- a/utils/lib/mbsedit.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Very simple multibyte buffer editor. Allows to maintaine the current - * position in the string, add and remove chars on the current position. - * - * This file may be distributed under the terms of the - * GNU Lesser General Public License. - * - * Copyright (C) 2017 Karel Zak - */ -#include -#include -#include -#include - -#include "mbsalign.h" -#include "mbsedit.h" - -struct mbs_editor *mbs_new_edit(char *buf, size_t bufsz, size_t ncells) -{ - struct mbs_editor *edit = calloc(1, sizeof(*edit)); - - if (edit) { - edit->buf = buf; - edit->max_bytes = bufsz; - edit->max_cells = ncells; - edit->cur_cells = mbs_safe_width(buf); - edit->cur_bytes = strlen(buf); - } - return edit; -} - -char *mbs_free_edit(struct mbs_editor *edit) -{ - char *ret = edit ? edit->buf : NULL; - - free(edit); - return ret; -} - -static size_t mbs_next(const char *str, size_t *ncells) -{ -#ifdef HAVE_WIDECHAR - wchar_t wc; - size_t n = 0; - - if (!str || !*str) - return 0; - - n = mbrtowc(&wc, str, MB_CUR_MAX, NULL); - *ncells = wcwidth(wc); - return n; -#else - if (!str || !*str) - return 0; - *ncells = 1; - return 1; -#endif -} - -static size_t mbs_prev(const char *start, const char *end, size_t *ncells) -{ -#ifdef HAVE_WIDECHAR - wchar_t wc = 0; - const char *p, *prev; - size_t n = 0; - - if (!start || !end || start == end || !*start) - return 0; - - prev = p = start; - while (p < end) { - n = mbrtowc(&wc, p, MB_CUR_MAX, NULL); - prev = p; - - if (n == (size_t) -1 || n == (size_t) -2) - p++; - else - p += n; - } - - if (prev == end) - return 0; - *ncells = wcwidth(wc); - return n; -#else - if (!start || !end || start == end || !*start) - return 0; - *ncells = 1; - return 1; -#endif -} - -int mbs_edit_goto(struct mbs_editor *edit, int where) -{ - switch (where) { - case MBS_EDIT_LEFT: - if (edit->cursor == 0) - return 1; - else { - size_t n, cells; - n = mbs_prev(edit->buf, edit->buf + edit->cursor, &cells); - if (n) { - edit->cursor -= n; - edit->cursor_cells -= cells; - } - } - break; - case MBS_EDIT_RIGHT: - if (edit->cursor_cells >= edit->cur_cells) - return 1; - else { - size_t n, cells; - n = mbs_next(edit->buf + edit->cursor, &cells); - if (n) { - edit->cursor += n; - edit->cursor_cells += cells; - } - } - break; - case MBS_EDIT_HOME: - edit->cursor = 0; - edit->cursor_cells = 0; - break; - case MBS_EDIT_END: - edit->cursor = edit->cur_bytes; - edit->cursor_cells = edit->cur_cells; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* Remove next MB from @str, returns number of removed bytes */ -static size_t remove_next(char *str, size_t *ncells) -{ - /* all in bytes! */ - size_t bytes, move_bytes, n; - - n = mbs_next(str, ncells); - bytes = strlen(str); - move_bytes = bytes - n; - - memmove(str, str + n, move_bytes); - str[bytes - n] = '\0'; - return n; -} - -static size_t mbs_insert(char *str, wint_t c, size_t *ncells) -{ - /* all in bytes! */ - size_t n = 1, bytes; - char *in; - -#ifdef HAVE_WIDECHAR - wchar_t wc = (wchar_t) c; - char in_buf[MB_CUR_MAX]; - - n = wctomb(in_buf, wc); - if (n == (size_t) -1) - return n; - *ncells = wcwidth(wc); - in = in_buf; -#else - *ncells = 1; - in = (char *) &c; -#endif - bytes = strlen(str); - - memmove(str + n, str, bytes); - memcpy(str, in, n); - str[bytes + n] = '\0'; - return n; -} - -static int mbs_edit_remove(struct mbs_editor *edit) -{ - size_t n, ncells; - - if (edit->cur_cells == 0 || edit->cursor >= edit->cur_bytes) - return 1; - - n = remove_next(edit->buf + edit->cursor, &ncells); - if (n == (size_t)-1) - return 1; - - edit->cur_bytes -= n; - edit->cur_cells = mbs_safe_width(edit->buf); - return 0; -} - -int mbs_edit_delete(struct mbs_editor *edit) -{ - if (edit->cursor >= edit->cur_bytes - && mbs_edit_goto(edit, MBS_EDIT_LEFT) == 1) - return 1; - - return mbs_edit_remove(edit); -} - -int mbs_edit_backspace(struct mbs_editor *edit) -{ - if (mbs_edit_goto(edit, MBS_EDIT_LEFT) == 0) - return mbs_edit_remove(edit); - return 1; -} - -int mbs_edit_insert(struct mbs_editor *edit, wint_t c) -{ - size_t n, ncells; - - if (edit->cur_bytes + MB_CUR_MAX > edit->max_bytes) - return 1; - - n = mbs_insert(edit->buf + edit->cursor, c, &ncells); - if (n == (size_t)-1) - return 1; - - edit->cursor += n; - edit->cursor_cells += ncells; - edit->cur_bytes += n; - edit->cur_cells = mbs_safe_width(edit->buf); - return 0; -} diff --git a/utils/lib/md5.c b/utils/lib/md5.c deleted file mode 100644 index 3765ab9..0000000 --- a/utils/lib/md5.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ -#include /* for memcpy() */ - -#include "md5.h" - -#if !defined(WORDS_BIGENDIAN) -# define byteReverse(buf, len) /* Nothing */ -#else -static void byteReverse(unsigned char *buf, unsigned longs); - -#ifndef ASM_MD5 -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - uint32_t t; - do { - t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32_t *) buf = t; - buf += 4; - } while (--longs); -} -#endif /* !ASM_MD5 */ -#endif /* !WORDS_BIGENDIAN */ - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void ul_MD5Init(struct UL_MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void ul_MD5Update(struct UL_MD5Context *ctx, unsigned char const *buf, unsigned len) -{ - uint32_t t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void ul_MD5Final(unsigned char digest[UL_MD5LENGTH], struct UL_MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform. - * Use memcpy to avoid aliasing problems. On most systems, - * this will be optimized away to the same code. - */ - memcpy(&ctx->in[14 * sizeof(uint32_t)], &ctx->bits[0], 4); - memcpy(&ctx->in[15 * sizeof(uint32_t)], &ctx->bits[1], 4); - - ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, UL_MD5LENGTH); - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -#ifndef ASM_MD5 - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void ul_MD5Transform(uint32_t buf[4], uint32_t const in[16]) -{ - register uint32_t a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#endif - diff --git a/utils/lib/monotonic.c b/utils/lib/monotonic.c deleted file mode 100644 index f0aeba6..0000000 --- a/utils/lib/monotonic.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Please, don't add this file to libcommon because clock_gettime() requires - * -lrt on systems with old libc. - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - */ -#include -#include -#ifdef HAVE_SYSINFO -#include -#endif -#include - -#include "c.h" -#include "monotonic.h" - -int get_boot_time(struct timeval *boot_time) -{ -#ifdef CLOCK_BOOTTIME - struct timespec hires_uptime; - struct timeval lores_uptime; -#endif - struct timeval now; -#ifdef HAVE_SYSINFO - struct sysinfo info; -#endif - - if (gettimeofday(&now, NULL) != 0) - return -errno; -#ifdef CLOCK_BOOTTIME - if (clock_gettime(CLOCK_BOOTTIME, &hires_uptime) == 0) { - TIMESPEC_TO_TIMEVAL(&lores_uptime, &hires_uptime); - timersub(&now, &lores_uptime, boot_time); - return 0; - } -#endif -#ifdef HAVE_SYSINFO - /* fallback */ - if (sysinfo(&info) != 0) - return -errno; - - boot_time->tv_sec = now.tv_sec - info.uptime; - boot_time->tv_usec = 0; - return 0; -#else - return -ENOSYS; -#endif -} - -time_t get_suspended_time(void) -{ -#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC) - struct timespec boot, mono; - - if (clock_gettime(CLOCK_BOOTTIME, &boot) == 0 && - clock_gettime(CLOCK_MONOTONIC, &mono) == 0) - return boot.tv_sec - mono.tv_sec; -#endif - return 0; -} - -int gettime_monotonic(struct timeval *tv) -{ -#ifdef CLOCK_MONOTONIC - /* Can slew only by ntp and adjtime */ - int ret; - struct timespec ts; - - /* Linux specific, can't slew */ - if (!(ret = clock_gettime(UL_CLOCK_MONOTONIC, &ts))) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; - } - return ret; -#else - return gettimeofday(tv, NULL); -#endif -} - - diff --git a/utils/lib/pager.c b/utils/lib/pager.c deleted file mode 100644 index b3cf6ee..0000000 --- a/utils/lib/pager.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Based on linux-perf/git scm - * - * Some modifications and simplifications for util-linux - * by Davidlohr Bueso - March 2012. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "xalloc.h" -#include "nls.h" -#include "ttyutils.h" -#include "pager.h" - -#define NULL_DEVICE "/dev/null" - -static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; - -struct child_process { - const char **argv; - pid_t pid; - int in; - int out; - int err; - - int org_err; - int org_out; - struct sigaction orig_sigint; - struct sigaction orig_sighup; - struct sigaction orig_sigterm; - struct sigaction orig_sigquit; - struct sigaction orig_sigpipe; - - unsigned no_stdin:1; - void (*preexec_cb)(void); -}; -static struct child_process pager_process; - -static inline void close_pair(int fd[2]) -{ - close(fd[0]); - close(fd[1]); -} - -static int start_command(struct child_process *cmd) -{ - int need_in; - int fdin[2]; - - /* - * In case of errors we must keep the promise to close FDs - * that have been passed in via ->in and ->out. - */ - need_in = !cmd->no_stdin && cmd->in < 0; - if (need_in) { - if (pipe(fdin) < 0) { - if (cmd->out > 0) - close(cmd->out); - return -1; - } - cmd->in = fdin[1]; - } - - fflush(NULL); - cmd->pid = fork(); - if (!cmd->pid) { - if (need_in) { - dup2(fdin[0], STDIN_FILENO); - close_pair(fdin); - } else if (cmd->in > 0) { - dup2(cmd->in, STDIN_FILENO); - close(cmd->in); - } - - cmd->preexec_cb(); - execvp(cmd->argv[0], (char *const*) cmd->argv); - errexec(cmd->argv[0]); - } - - if (cmd->pid < 0) { - if (need_in) - close_pair(fdin); - else if (cmd->in) - close(cmd->in); - return -1; - } - - if (need_in) - close(fdin[0]); - else if (cmd->in) - close(cmd->in); - return 0; -} - -static int wait_or_whine(pid_t pid) -{ - for (;;) { - int status, code; - pid_t waiting = waitpid(pid, &status, 0); - - if (waiting < 0) { - if (errno == EINTR) - continue; - err(EXIT_FAILURE, _("waitpid failed (%s)"), strerror(errno)); - } - if (waiting != pid) - return -1; - if (WIFSIGNALED(status)) - return -1; - - if (!WIFEXITED(status)) - return -1; - code = WEXITSTATUS(status); - switch (code) { - case 127: - return -1; - case 0: - return 0; - default: - return -1; - } - } -} - -static int finish_command(struct child_process *cmd) -{ - return wait_or_whine(cmd->pid); -} - -static void pager_preexec(void) -{ - /* - * Work around bug in "less" by not starting it until we - * have real input - */ - fd_set in, ex; - - FD_ZERO(&in); - FD_SET(STDIN_FILENO, &in); - ex = in; - - select(STDIN_FILENO + 1, &in, NULL, &ex, NULL); - - if (setenv("LESS", "FRSX", 0) != 0) - warn(_("failed to set the %s environment variable"), "LESS"); -} - -static void wait_for_pager(void) -{ - if (pager_process.pid == 0) - return; - - fflush(stdout); - fflush(stderr); - /* signal EOF to pager */ - close(STDOUT_FILENO); - close(STDERR_FILENO); - finish_command(&pager_process); -} - -static void wait_for_pager_signal(int signo) -{ - wait_for_pager(); - raise(signo); -} - -static int has_command(const char *cmd) -{ - const char *path; - char *p, *s; - int rc = 0; - - if (!cmd) - goto done; - if (*cmd == '/') { - rc = access(cmd, X_OK) == 0; - goto done; - } - - path = getenv("PATH"); - if (!path) - goto done; - p = xstrdup(path); - if (!p) - goto done; - - for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) { - int fd = open(s, O_RDONLY|O_CLOEXEC); - if (fd < 0) - continue; - rc = faccessat(fd, cmd, X_OK, 0) == 0; - close(fd); - if (rc) - break; - } - free(p); -done: - /*fprintf(stderr, "has PAGER %s rc=%d\n", cmd, rc);*/ - return rc; -} - -static void __setup_pager(void) -{ - const char *pager = getenv("PAGER"); - struct sigaction sa; - - if (!isatty(STDOUT_FILENO)) - return; - - if (!pager) - pager = "less"; - else if (!*pager || !strcmp(pager, "cat")) - return; - - if (!has_command(pager)) - return; - - /* spawn the pager */ - pager_argv[2] = pager; - pager_process.argv = pager_argv; - pager_process.in = -1; - pager_process.preexec_cb = pager_preexec; - - if (start_command(&pager_process)) - return; - - /* original process continues, but writes to the pipe */ - dup2(pager_process.in, STDOUT_FILENO); - if (isatty(STDERR_FILENO)) - dup2(pager_process.in, STDERR_FILENO); - close(pager_process.in); - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = wait_for_pager_signal; - - /* this makes sure that the parent terminates after the pager */ - sigaction(SIGINT, &sa, &pager_process.orig_sigint); - sigaction(SIGHUP, &sa, &pager_process.orig_sighup); - sigaction(SIGTERM, &sa, &pager_process.orig_sigterm); - sigaction(SIGQUIT, &sa, &pager_process.orig_sigquit); - sigaction(SIGPIPE, &sa, &pager_process.orig_sigpipe); -} - -/* Setup pager and redirects output to the $PAGER. The pager is closed at exit. - */ -void pager_redirect(void) -{ - if (pager_process.pid) - return; /* already running */ - - __setup_pager(); - - atexit(wait_for_pager); -} - -/* Setup pager and redirect output, the pager may be closed by pager_close(). - */ -void pager_open(void) -{ - if (pager_process.pid) - return; /* already running */ - - pager_process.org_out = dup(STDOUT_FILENO); - pager_process.org_err = dup(STDERR_FILENO); - - __setup_pager(); -} - -/* Close pager and restore original std{out,err}. - */ -void pager_close(void) -{ - if (pager_process.pid == 0) - return; - - wait_for_pager(); - - /* restore original output */ - dup2(pager_process.org_out, STDOUT_FILENO); - dup2(pager_process.org_err, STDERR_FILENO); - - close(pager_process.org_out); - close(pager_process.org_err); - - /* restore original segnals setting */ - sigaction(SIGINT, &pager_process.orig_sigint, NULL); - sigaction(SIGHUP, &pager_process.orig_sighup, NULL); - sigaction(SIGTERM, &pager_process.orig_sigterm, NULL); - sigaction(SIGQUIT, &pager_process.orig_sigquit, NULL); - sigaction(SIGPIPE, &pager_process.orig_sigpipe, NULL); - - memset(&pager_process, 0, sizeof(pager_process)); -} - -#ifdef TEST_PROGRAM_PAGER - -#define MAX 255 - -int main(int argc __attribute__ ((__unused__)), - char *argv[] __attribute__ ((__unused__))) -{ - int i; - - pager_redirect(); - for (i = 0; i < MAX; i++) - printf("%d\n", i); - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_PAGER */ diff --git a/utils/lib/path.c b/utils/lib/path.c deleted file mode 100644 index 75fa853..0000000 --- a/utils/lib/path.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * Simple functions to access files. Paths can be globally prefixed to read - * data from an alternative source (e.g. a /proc dump for regression tests). - * - * The paths is possible to format by printf-like way for functions with "f" - * postfix in the name (e.g. readf, openf, ... ul_path_readf_u64()). - * - * The ul_path_read_* API is possible to use without path_cxt handler. In this - * case is not possible to use global prefix and printf-like formatting. - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak [February 2018] - */ -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "fileutils.h" -#include "all-io.h" -#include "path.h" -#include "debug.h" -#include "strutils.h" - -/* - * Debug stuff (based on include/debug.h) - */ -static UL_DEBUG_DEFINE_MASK(ulpath); -UL_DEBUG_DEFINE_MASKNAMES(ulpath) = UL_DEBUG_EMPTY_MASKNAMES; - -#define ULPATH_DEBUG_INIT (1 << 1) -#define ULPATH_DEBUG_CXT (1 << 2) - -#define DBG(m, x) __UL_DBG(ulpath, ULPATH_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(ulpath, ULPATH_DEBUG_, m, x) - -#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpath) -#include "debugobj.h" - -void ul_path_init_debug(void) -{ - if (ulpath_debug_mask) - return; - __UL_INIT_DEBUG_FROM_ENV(ulpath, ULPATH_DEBUG_, 0, ULPATH_DEBUG); -} - -struct path_cxt *ul_new_path(const char *dir, ...) -{ - struct path_cxt *pc = calloc(1, sizeof(*pc)); - - if (!pc) - return NULL; - - DBG(CXT, ul_debugobj(pc, "alloc")); - - pc->refcount = 1; - pc->dir_fd = -1; - - if (dir) { - int rc; - va_list ap; - - va_start(ap, dir); - rc = vasprintf(&pc->dir_path, dir, ap); - va_end(ap); - - if (rc < 0 || !pc->dir_path) - goto fail; - } - return pc; -fail: - ul_unref_path(pc); - return NULL; -} - -void ul_ref_path(struct path_cxt *pc) -{ - if (pc) - pc->refcount++; -} - -void ul_unref_path(struct path_cxt *pc) -{ - if (!pc) - return; - - pc->refcount--; - - if (pc->refcount <= 0) { - DBG(CXT, ul_debugobj(pc, "dealloc")); - if (pc->dialect) - pc->free_dialect(pc); - ul_path_close_dirfd(pc); - free(pc->dir_path); - free(pc->prefix); - free(pc); - } -} - -int ul_path_set_prefix(struct path_cxt *pc, const char *prefix) -{ - char *p = NULL; - - assert(pc->dir_fd < 0); - - if (prefix) { - p = strdup(prefix); - if (!p) - return -ENOMEM; - } - - free(pc->prefix); - pc->prefix = p; - DBG(CXT, ul_debugobj(pc, "new prefix: '%s'", p)); - return 0; -} - -const char *ul_path_get_prefix(struct path_cxt *pc) -{ - return pc ? pc->prefix : NULL; -} - -int ul_path_set_dir(struct path_cxt *pc, const char *dir) -{ - char *p = NULL; - - if (dir) { - p = strdup(dir); - if (!p) - return -ENOMEM; - } - - if (pc->dir_fd >= 0) { - close(pc->dir_fd); - pc->dir_fd = -1; - } - - free(pc->dir_path); - pc->dir_path = p; - DBG(CXT, ul_debugobj(pc, "new dir: '%s'", p)); - return 0; -} - -const char *ul_path_get_dir(struct path_cxt *pc) -{ - return pc ? pc->dir_path : NULL; -} - -int ul_path_set_dialect(struct path_cxt *pc, void *data, void free_data(struct path_cxt *)) -{ - pc->dialect = data; - pc->free_dialect = free_data; - DBG(CXT, ul_debugobj(pc, "(re)set dialect")); - return 0; -} - -void *ul_path_get_dialect(struct path_cxt *pc) -{ - return pc ? pc->dialect : NULL; -} - -int ul_path_set_enoent_redirect(struct path_cxt *pc, int (*func)(struct path_cxt *, const char *, int *)) -{ - pc->redirect_on_enoent = func; - return 0; -} - -static const char *get_absdir(struct path_cxt *pc) -{ - int rc; - const char *dirpath; - - if (!pc->prefix) - return pc->dir_path; - - dirpath = pc->dir_path; - if (!dirpath) - return pc->prefix; - if (*dirpath == '/') - dirpath++; - - rc = snprintf(pc->path_buffer, sizeof(pc->path_buffer), "%s/%s", pc->prefix, dirpath); - if (rc < 0) - return NULL; - if ((size_t)rc >= sizeof(pc->path_buffer)) { - errno = ENAMETOOLONG; - return NULL; - } - - return pc->path_buffer; -} - -int ul_path_is_accessible(struct path_cxt *pc) -{ - const char *path; - assert(pc); - - if (pc->dir_fd >= 0) - return 1; - - path = get_absdir(pc); - if (!path) - return 0; - return access(path, F_OK) == 0; -} - -int ul_path_get_dirfd(struct path_cxt *pc) -{ - assert(pc); - assert(pc->dir_path); - - if (pc->dir_fd < 0) { - const char *path = get_absdir(pc); - if (!path) - return -errno; - - DBG(CXT, ul_debugobj(pc, "opening dir: '%s'", path)); - pc->dir_fd = open(path, O_RDONLY|O_CLOEXEC); - } - - return pc->dir_fd; -} - -/* Note that next ul_path_get_dirfd() will reopen the directory */ -void ul_path_close_dirfd(struct path_cxt *pc) -{ - assert(pc); - - if (pc->dir_fd >= 0) { - DBG(CXT, ul_debugobj(pc, "closing dir")); - close(pc->dir_fd); - pc->dir_fd = -1; - } -} - -int ul_path_isopen_dirfd(struct path_cxt *pc) -{ - return pc && pc->dir_fd >= 0; -} - -static const char *ul_path_mkpath(struct path_cxt *pc, const char *path, va_list ap) -{ - int rc; - - errno = 0; - - rc = vsnprintf(pc->path_buffer, sizeof(pc->path_buffer), path, ap); - if (rc < 0) { - if (!errno) - errno = EINVAL; - return NULL; - } - - if ((size_t)rc >= sizeof(pc->path_buffer)) { - errno = ENAMETOOLONG; - return NULL; - } - - return pc->path_buffer; -} - -char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...) -{ - if (path) { - int rc; - va_list ap; - const char *tail = NULL, *dirpath = pc->dir_path; - - va_start(ap, path); - tail = ul_path_mkpath(pc, path, ap); - va_end(ap); - - if (dirpath && *dirpath == '/') - dirpath++; - if (tail && *tail == '/') - tail++; - - rc = snprintf(buf, bufsz, "%s/%s/%s", - pc->prefix ? pc->prefix : "", - dirpath ? dirpath : "", - tail ? tail : ""); - - if ((size_t)rc >= bufsz) { - errno = ENAMETOOLONG; - return NULL; - } - } else { - const char *tmp = get_absdir(pc); - - if (!tmp) - return NULL; - xstrncpy(buf, tmp, bufsz); - } - - return buf; -} - - -int ul_path_access(struct path_cxt *pc, int mode, const char *path) -{ - int rc; - - if (!pc) { - rc = access(path, mode); - DBG(CXT, ul_debug("access '%s' [no context, rc=%d]", path, rc)); - } else { - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - if (*path == '/') - path++; - - rc = faccessat(dir, path, mode, 0); - - if (rc && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - rc = faccessat(dir, path, mode, 0); - - DBG(CXT, ul_debugobj(pc, "access: '%s' [rc=%d]", path, rc)); - } - return rc; -} - -int ul_path_accessf(struct path_cxt *pc, int mode, const char *path, ...) -{ - va_list ap; - const char *p; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_access(pc, mode, p); -} - -int ul_path_stat(struct path_cxt *pc, struct stat *sb, const char *path) -{ - int rc; - - if (!pc) { - rc = stat(path, sb); - DBG(CXT, ul_debug("stat '%s' [no context, rc=%d]", path, rc)); - } else { - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - if (*path == '/') - path++; - - rc = fstatat(dir, path, sb, 0); - - if (rc && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - rc = fstatat(dir, path, sb, 0); - - DBG(CXT, ul_debugobj(pc, "stat '%s' [rc=%d]", path, rc)); - } - return rc; -} - -int ul_path_open(struct path_cxt *pc, int flags, const char *path) -{ - int fd; - - if (!pc) { - fd = open(path, flags); - DBG(CXT, ul_debug("opening '%s' [no context]", path)); - } else { - int fdx; - int dir = ul_path_get_dirfd(pc); - if (dir < 0) - return dir; - - if (*path == '/') - path++; - - fdx = fd = openat(dir, path, flags); - - if (fd < 0 && errno == ENOENT - && pc->redirect_on_enoent - && pc->redirect_on_enoent(pc, path, &dir) == 0) - fd = openat(dir, path, flags); - - DBG(CXT, ul_debugobj(pc, "opening '%s'%s", path, fdx != fd ? " [redirected]" : "")); - } - return fd; -} - -int ul_path_vopenf(struct path_cxt *pc, int flags, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? -errno : ul_path_open(pc, flags, p); -} - -int ul_path_openf(struct path_cxt *pc, int flags, const char *path, ...) -{ - va_list ap; - int rc; - - va_start(ap, path); - rc = ul_path_vopenf(pc, flags, path, ap); - va_end(ap); - - return rc; -} - -/* - * Maybe stupid, but good enough ;-) - */ -static int mode2flags(const char *mode) -{ - int flags = 0; - const char *p; - - for (p = mode; p && *p; p++) { - if (*p == 'r' && *(p + 1) == '+') - flags |= O_RDWR; - else if (*p == 'r') - flags |= O_RDONLY; - - else if (*p == 'w' && *(p + 1) == '+') - flags |= O_RDWR | O_TRUNC; - else if (*p == 'w') - flags |= O_WRONLY | O_TRUNC; - - else if (*p == 'a' && *(p + 1) == '+') - flags |= O_RDWR | O_APPEND; - else if (*p == 'a') - flags |= O_WRONLY | O_APPEND; -#ifdef O_CLOEXEC - else if (*p == *UL_CLOEXECSTR) - flags |= O_CLOEXEC; -#endif - } - - return flags; -} - -FILE *ul_path_fopen(struct path_cxt *pc, const char *mode, const char *path) -{ - int flags = mode2flags(mode); - int fd = ul_path_open(pc, flags, path); - - if (fd < 0) - return NULL; - - return fdopen(fd, mode); -} - - -FILE *ul_path_vfopenf(struct path_cxt *pc, const char *mode, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? NULL : ul_path_fopen(pc, mode, p); -} - -FILE *ul_path_fopenf(struct path_cxt *pc, const char *mode, const char *path, ...) -{ - FILE *f; - va_list ap; - - va_start(ap, path); - f = ul_path_vfopenf(pc, mode, path, ap); - va_end(ap); - - return f; -} - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_opendir(struct path_cxt *pc, const char *path) -{ - DIR *dir; - int fd = -1; - - if (path) - fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path); - else if (pc->dir_path) { - int dirfd; - - DBG(CXT, ul_debugobj(pc, "duplicate dir path")); - dirfd = ul_path_get_dirfd(pc); - if (dirfd >= 0) - fd = dup_fd_cloexec(dirfd, STDERR_FILENO + 1); - } - - if (fd < 0) - return NULL; - - dir = fdopendir(fd); - if (!dir) { - close(fd); - return NULL; - } - if (!path) - rewinddir(dir); - return dir; -} - - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_vopendirf(struct path_cxt *pc, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? NULL : ul_path_opendir(pc, p); -} - -/* - * Open directory @path in read-onl mode. If the path is NULL then duplicate FD - * to the directory addressed by @pc. - */ -DIR *ul_path_opendirf(struct path_cxt *pc, const char *path, ...) -{ - va_list ap; - DIR *dir; - - va_start(ap, path); - dir = ul_path_vopendirf(pc, path, ap); - va_end(ap); - - return dir; -} - -/* - * If @path is NULL then readlink is called on @pc directory. - */ -ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path) -{ - int dirfd; - - if (!path) { - const char *p = get_absdir(pc); - if (!p) - return -errno; - return readlink(p, buf, bufsiz); - } - - dirfd = ul_path_get_dirfd(pc); - if (dirfd < 0) - return dirfd; - - if (*path == '/') - path++; - - return readlinkat(dirfd, path, buf, bufsiz); -} - -/* - * If @path is NULL then readlink is called on @pc directory. - */ -ssize_t ul_path_readlinkf(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_readlink(pc, buf, bufsiz, p); -} - -int ul_path_read(struct path_cxt *pc, char *buf, size_t len, const char *path) -{ - int rc, errsv; - int fd; - - fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - DBG(CXT, ul_debug(" reading '%s'", path)); - rc = read_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_vreadf(struct path_cxt *pc, char *buf, size_t len, const char *path, va_list ap) -{ - const char *p = ul_path_mkpath(pc, path, ap); - - return !p ? -errno : ul_path_read(pc, buf, len, p); -} - -int ul_path_readf(struct path_cxt *pc, char *buf, size_t len, const char *path, ...) -{ - va_list ap; - int rc; - - va_start(ap, path); - rc = ul_path_vreadf(pc, buf, len, path, ap); - va_end(ap); - - return rc; -} - - -/* - * Returns newly allocated buffer with data from file. Maximal size is BUFSIZ - * (send patch if you need something bigger;-) - * - * Returns size of the string! - */ -int ul_path_read_string(struct path_cxt *pc, char **str, const char *path) -{ - char buf[BUFSIZ]; - int rc; - - if (!str) - return -EINVAL; - - *str = NULL; - rc = ul_path_read(pc, buf, sizeof(buf) - 1, path); - if (rc < 0) - return rc; - - /* Remove tailing newline (usual in sysfs) */ - if (rc > 0 && *(buf + rc - 1) == '\n') - --rc; - - buf[rc] = '\0'; - *str = strdup(buf); - if (!*str) - rc = -ENOMEM; - - return rc; -} - -int ul_path_readf_string(struct path_cxt *pc, char **str, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_string(pc, str, p); -} - -int ul_path_read_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path) -{ - int rc = ul_path_read(pc, buf, bufsz - 1, path); - if (rc < 0) - return rc; - - /* Remove tailing newline (usual in sysfs) */ - if (rc > 0 && *(buf + rc - 1) == '\n') - buf[--rc] = '\0'; - else - buf[rc - 1] = '\0'; - - return rc; -} - -int ul_path_readf_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_buffer(pc, buf, bufsz, p); -} - -int ul_path_scanf(struct path_cxt *pc, const char *path, const char *fmt, ...) -{ - FILE *f; - va_list fmt_ap; - int rc; - - f = ul_path_fopen(pc, "r" UL_CLOEXECSTR, path); - if (!f) - return -EINVAL; - - DBG(CXT, ul_debug(" fscanf [%s] '%s'", fmt, path)); - - va_start(fmt_ap, fmt); - rc = vfscanf(f, fmt, fmt_ap); - va_end(fmt_ap); - - fclose(f); - return rc; -} - -int ul_path_scanff(struct path_cxt *pc, const char *path, va_list ap, const char *fmt, ...) -{ - FILE *f; - va_list fmt_ap; - int rc; - - f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap); - if (!f) - return -EINVAL; - - va_start(fmt_ap, fmt); - rc = vfscanf(f, fmt, fmt_ap); - va_end(fmt_ap); - - fclose(f); - return rc; -} - - -int ul_path_read_s64(struct path_cxt *pc, int64_t *res, const char *path) -{ - int64_t x = 0; - int rc; - - rc = ul_path_scanf(pc, path, "%"SCNd64, &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_s64(pc, res, p); -} - -int ul_path_read_u64(struct path_cxt *pc, uint64_t *res, const char *path) -{ - uint64_t x = 0; - int rc; - - rc = ul_path_scanf(pc, path, "%"SCNu64, &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_u64(struct path_cxt *pc, uint64_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_u64(pc, res, p); -} - -int ul_path_read_s32(struct path_cxt *pc, int *res, const char *path) -{ - int rc, x = 0; - - rc = ul_path_scanf(pc, path, "%d", &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_s32(struct path_cxt *pc, int *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_s32(pc, res, p); -} - -int ul_path_read_u32(struct path_cxt *pc, unsigned int *res, const char *path) -{ - int rc; - unsigned int x; - - rc = ul_path_scanf(pc, path, "%u", &x); - if (rc != 1) - return -1; - if (res) - *res = x; - return 0; -} - -int ul_path_readf_u32(struct path_cxt *pc, unsigned int *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_u32(pc, res, p); -} - -int ul_path_read_majmin(struct path_cxt *pc, dev_t *res, const char *path) -{ - int rc, maj, min; - - rc = ul_path_scanf(pc, path, "%d:%d", &maj, &min); - if (rc != 2) - return -1; - if (res) - *res = makedev(maj, min); - return 0; -} - -int ul_path_readf_majmin(struct path_cxt *pc, dev_t *res, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_read_majmin(pc, res, p); -} - -int ul_path_write_string(struct path_cxt *pc, const char *str, const char *path) -{ - int rc, errsv; - int fd; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - rc = write_all(fd, str, strlen(str)); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_writef_string(struct path_cxt *pc, const char *str, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_write_string(pc, str, p); -} - -int ul_path_write_s64(struct path_cxt *pc, int64_t num, const char *path) -{ - char buf[sizeof(stringify_value(LLONG_MAX))]; - int rc, errsv; - int fd, len; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - len = snprintf(buf, sizeof(buf), "%" PRId64, num); - if (len < 0 || (size_t) len >= sizeof(buf)) - rc = len < 0 ? -errno : -E2BIG; - else - rc = write_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_write_u64(struct path_cxt *pc, uint64_t num, const char *path) -{ - char buf[sizeof(stringify_value(ULLONG_MAX))]; - int rc, errsv; - int fd, len; - - fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path); - if (fd < 0) - return -errno; - - len = snprintf(buf, sizeof(buf), "%" PRIu64, num); - if (len < 0 || (size_t) len >= sizeof(buf)) - rc = len < 0 ? -errno : -E2BIG; - else - rc = write_all(fd, buf, len); - - errsv = errno; - close(fd); - errno = errsv; - return rc; -} - -int ul_path_writef_u64(struct path_cxt *pc, uint64_t num, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_write_u64(pc, num, p); - -} - -int ul_path_count_dirents(struct path_cxt *pc, const char *path) -{ - DIR *dir; - int r = 0; - - dir = ul_path_opendir(pc, path); - if (!dir) - return 0; - - while (xreaddir(dir)) r++; - - closedir(dir); - return r; -} - -int ul_path_countf_dirents(struct path_cxt *pc, const char *path, ...) -{ - const char *p; - va_list ap; - - va_start(ap, path); - p = ul_path_mkpath(pc, path, ap); - va_end(ap); - - return !p ? -errno : ul_path_count_dirents(pc, p); -} - -/* - * Like fopen() but, @path is always prefixed by @prefix. This function is - * useful in case when ul_path_* API is overkill. - */ -FILE *ul_prefix_fopen(const char *prefix, const char *path, const char *mode) -{ - char buf[PATH_MAX]; - - if (!path) - return NULL; - if (!prefix) - return fopen(path, mode); - if (*path == '/') - path++; - - snprintf(buf, sizeof(buf), "%s/%s", prefix, path); - return fopen(buf, mode); -} - -#ifdef HAVE_CPU_SET_T -static int ul_path_cpuparse(struct path_cxt *pc, cpu_set_t **set, int maxcpus, int islist, const char *path, va_list ap) -{ - FILE *f; - size_t setsize, len = maxcpus * 7; - char buf[len]; - int rc; - - *set = NULL; - - f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap); - if (!f) - return -errno; - - rc = fgets(buf, len, f) == NULL ? -errno : 0; - fclose(f); - - if (rc) - return rc; - - len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - *set = cpuset_alloc(maxcpus, &setsize, NULL); - if (!*set) - return -ENOMEM; - - if (islist) { - if (cpulist_parse(buf, *set, setsize, 0)) { - cpuset_free(*set); - return -EINVAL; - } - } else { - if (cpumask_parse(buf, *set, setsize)) { - cpuset_free(*set); - return -EINVAL; - } - } - return 0; -} - -int ul_path_readf_cpuset(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...) -{ - va_list ap; - int rc = 0; - - va_start(ap, path); - rc = ul_path_cpuparse(pc, set, maxcpus, 0, path, ap); - va_end(ap); - - return rc; -} - -int ul_path_readf_cpulist(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...) -{ - va_list ap; - int rc = 0; - - va_start(ap, path); - rc = ul_path_cpuparse(pc, set, maxcpus, 1, path, ap); - va_end(ap); - - return rc; -} - -#endif /* HAVE_CPU_SET_T */ - - -#ifdef TEST_PROGRAM_PATH -#include - -static void __attribute__((__noreturn__)) usage(void) -{ - fprintf(stdout, " %s [options] \n\n", program_invocation_short_name); - fputs(" -p, --prefix redirect hardcoded paths to \n", stdout); - - fputs(" Commands:\n", stdout); - fputs(" read-u64 read uint64_t from file\n", stdout); - fputs(" read-s64 read int64_t from file\n", stdout); - fputs(" read-u32 read uint32_t from file\n", stdout); - fputs(" read-s32 read int32_t from file\n", stdout); - fputs(" read-string read string from file\n", stdout); - fputs(" read-majmin read devno from file\n", stdout); - fputs(" read-link read symlink\n", stdout); - fputs(" write-string write string from file\n", stdout); - fputs(" write-u64 write uint64_t from file\n", stdout); - - exit(EXIT_SUCCESS); -} - -int main(int argc, char *argv[]) -{ - int c; - const char *prefix = NULL, *dir, *file, *command; - struct path_cxt *pc = NULL; - - static const struct option longopts[] = { - { "prefix", 1, NULL, 'p' }, - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - - while((c = getopt_long(argc, argv, "p:h", longopts, NULL)) != -1) { - switch(c) { - case 'p': - prefix = optarg; - break; - case 'h': - usage(); - break; - default: - err(EXIT_FAILURE, "try --help"); - } - } - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - dir = argv[optind++]; - - ul_path_init_debug(); - - pc = ul_new_path(dir); - if (!pc) - err(EXIT_FAILURE, "failed to initialize path context"); - if (prefix) - ul_path_set_prefix(pc, prefix); - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - command = argv[optind++]; - - if (strcmp(command, "read-u32") == 0) { - uint32_t res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_u32(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %u\n", file, res); - - if (ul_path_readf_u32(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %u\n", file, res); - - } else if (strcmp(command, "read-s32") == 0) { - int32_t res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_s32(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %d\n", file, res); - - if (ul_path_readf_s32(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %d\n", file, res); - - } else if (strcmp(command, "read-u64") == 0) { - uint64_t res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_u64(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %" PRIu64 "\n", file, res); - - if (ul_path_readf_u64(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %" PRIu64 "\n", file, res); - - } else if (strcmp(command, "read-s64") == 0) { - int64_t res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_s64(pc, &res, file) != 0) - err(EXIT_FAILURE, "read u64 failed"); - printf("read: %s: %" PRIu64 "\n", file, res); - - if (ul_path_readf_s64(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf u64 failed"); - printf("readf: %s: %" PRIu64 "\n", file, res); - - } else if (strcmp(command, "read-majmin") == 0) { - dev_t res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_majmin(pc, &res, file) != 0) - err(EXIT_FAILURE, "read maj:min failed"); - printf("read: %s: %d\n", file, (int) res); - - if (ul_path_readf_majmin(pc, &res, "%s", file) != 0) - err(EXIT_FAILURE, "readf maj:min failed"); - printf("readf: %s: %d\n", file, (int) res); - - } else if (strcmp(command, "read-string") == 0) { - char *res; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_read_string(pc, &res, file) < 0) - err(EXIT_FAILURE, "read string failed"); - printf("read: %s: %s\n", file, res); - - if (ul_path_readf_string(pc, &res, "%s", file) < 0) - err(EXIT_FAILURE, "readf string failed"); - printf("readf: %s: %s\n", file, res); - - } else if (strcmp(command, "read-link") == 0) { - char res[PATH_MAX]; - - if (optind == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - - if (ul_path_readlink(pc, res, sizeof(res), file) < 0) - err(EXIT_FAILURE, "read symlink failed"); - printf("read: %s: %s\n", file, res); - - if (ul_path_readlinkf(pc, res, sizeof(res), "%s", file) < 0) - err(EXIT_FAILURE, "readf symlink failed"); - printf("readf: %s: %s\n", file, res); - - } else if (strcmp(command, "write-string") == 0) { - char *str; - - if (optind + 1 == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - str = argv[optind++]; - - if (ul_path_write_string(pc, str, file) != 0) - err(EXIT_FAILURE, "write string failed"); - if (ul_path_writef_string(pc, str, "%s", file) != 0) - err(EXIT_FAILURE, "writef string failed"); - - } else if (strcmp(command, "write-u64") == 0) { - uint64_t num; - - if (optind + 1 == argc) - errx(EXIT_FAILURE, " not defined"); - file = argv[optind++]; - num = strtoumax(argv[optind++], NULL, 0); - - if (ul_path_write_u64(pc, num, file) != 0) - err(EXIT_FAILURE, "write u64 failed"); - if (ul_path_writef_u64(pc, num, "%s", file) != 0) - err(EXIT_FAILURE, "writef u64 failed"); - } - - ul_unref_path(pc); - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_PATH */ - diff --git a/utils/lib/plymouth-ctrl.c b/utils/lib/plymouth-ctrl.c deleted file mode 100644 index 2d3deda..0000000 --- a/utils/lib/plymouth-ctrl.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * plymouth-ctrl.c Simply communications with plymouthd - * to avoid forked sub processes and/or - * missed plymouth send commands tool - * due a plymouthd replacement. - * - * Copyright (c) 2016 SUSE Linux GmbH, All rights reserved. - * Copyright (c) 2016 Werner Fink - * - * 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; either version 2, or (at your option) - * any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * Author: Werner Fink - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "all-io.h" -#include "c.h" -#include "nls.h" -#include "plymouth-ctrl.h" - -static int can_read(int fd, const long timeout) -{ - struct pollfd fds = { - .fd = fd, - .events = POLLIN|POLLPRI, - .revents = 0, - }; - int ret; - - do { - ret = poll(&fds, 1, timeout); - } while ((ret < 0) && (errno == EINTR)); - - return (ret == 1) && (fds.revents & (POLLIN|POLLPRI)); -} - -static int open_un_socket_and_connect(void) -{ - /* The abstract UNIX socket of plymouth */ - struct sockaddr_un su = { - .sun_family = AF_UNIX, - .sun_path = PLYMOUTH_SOCKET_PATH, - }; - const int one = 1; - int fd, ret; - - fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (fd < 0) { - warnx(_("cannot open UNIX socket")); - goto err; - } - - ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); - if (ret < 0) { - warnx(_("cannot set option for UNIX socket")); - close(fd); - fd = -1; - goto err; - } - - /* Note, the abstract PLYMOUTH_SOCKET_PATH has a leading NULL byte */ - ret = connect(fd, (struct sockaddr *) &su, - offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1)); - if (ret < 0) { - if (errno != ECONNREFUSED) - warnx(_("cannot connect on UNIX socket")); - close(fd); - fd = -1; - goto err; - } -err: - return fd; -} - -int plymouth_command(int cmd, ...) -{ - uint8_t answer[2], command[2]; - struct sigaction sp, op; - int fdsock = -1, ret = 0; - - sigemptyset (&sp.sa_mask); - sp.sa_handler = SIG_IGN; - sp.sa_flags = SA_RESTART; - sigaction(SIGPIPE, &sp, &op); - - /* The plymouthd does read at least two bytes. */ - command[1] = '\0'; - switch (cmd) { - case MAGIC_PING: - fdsock = open_un_socket_and_connect(); - if (fdsock >= 0) { - command[0] = cmd; - write_all(fdsock, command, sizeof(command)); - } - break; - case MAGIC_QUIT: - fdsock = open_un_socket_and_connect(); - if (fdsock >= 0) { - command[0] = cmd; - write_all(fdsock, command, sizeof(command)); - } - break; - default: - warnx(_("the plymouth request %c is not implemented"), cmd); - case '?': - goto err; - } - - answer[0] = '\0'; - if (fdsock >= 0) { - if (can_read(fdsock, 1000)) - read_all(fdsock, (char *) &answer[0], sizeof(answer)); - close(fdsock); - } - sigaction(SIGPIPE, &op, NULL); - ret = (answer[0] == ANSWER_ACK) ? 1 : 0; -err: - return ret; -} - diff --git a/utils/lib/procutils.c b/utils/lib/procutils.c deleted file mode 100644 index 8fb5d5c..0000000 --- a/utils/lib/procutils.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2011 Davidlohr Bueso - * - * procutils.c: General purpose procfs parsing utilities - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 Library Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "procutils.h" -#include "fileutils.h" -#include "all-io.h" -#include "c.h" - -/* - * @pid: process ID for which we want to obtain the threads group - * - * Returns: newly allocated tasks structure - */ -struct proc_tasks *proc_open_tasks(pid_t pid) -{ - struct proc_tasks *tasks; - char path[PATH_MAX]; - - sprintf(path, "/proc/%d/task/", pid); - - tasks = malloc(sizeof(struct proc_tasks)); - if (tasks) { - tasks->dir = opendir(path); - if (tasks->dir) - return tasks; - } - - free(tasks); - return NULL; -} - -/* - * @tasks: allocated tasks structure - * - * Returns: nothing - */ -void proc_close_tasks(struct proc_tasks *tasks) -{ - if (tasks && tasks->dir) - closedir(tasks->dir); - free(tasks); -} - -/* - * @tasks: allocated task structure - * @tid: [output] one of the thread IDs belonging to the thread group - * If when an error occurs, it is set to 0. - * - * Returns: 0 on success, 1 on end, -1 on failure or no more threads - */ -int proc_next_tid(struct proc_tasks *tasks, pid_t *tid) -{ - struct dirent *d; - char *end; - - if (!tasks || !tid) - return -EINVAL; - - *tid = 0; - errno = 0; - - do { - d = readdir(tasks->dir); - if (!d) - return errno ? -1 : 1; /* error or end-of-dir */ - - if (!isdigit((unsigned char) *d->d_name)) - continue; - errno = 0; - *tid = (pid_t) strtol(d->d_name, &end, 10); - if (errno || d->d_name == end || (end && *end)) - return -1; - - } while (!*tid); - - return 0; -} - -/* returns process command path, use free() for result */ -static char *proc_file_strdup(pid_t pid, const char *name) -{ - char buf[BUFSIZ], *res = NULL; - ssize_t sz = 0; - size_t i; - int fd; - - snprintf(buf, sizeof(buf), "/proc/%d/%s", (int) pid, name); - fd = open(buf, O_RDONLY); - if (fd < 0) - goto done; - - sz = read_all(fd, buf, sizeof(buf)); - if (sz <= 0) - goto done; - - for (i = 0; i < (size_t) sz; i++) { - - if (buf[i] == '\0') - buf[i] = ' '; - } - buf[sz - 1] = '\0'; - res = strdup(buf); -done: - if (fd >= 0) - close(fd); - return res; -} - -/* returns process command path, use free() for result */ -char *proc_get_command(pid_t pid) -{ - return proc_file_strdup(pid, "cmdline"); -} - -/* returns process command name, use free() for result */ -char *proc_get_command_name(pid_t pid) -{ - return proc_file_strdup(pid, "comm"); -} - -struct proc_processes *proc_open_processes(void) -{ - struct proc_processes *ps; - - ps = calloc(1, sizeof(struct proc_processes)); - if (ps) { - ps->dir = opendir("/proc"); - if (ps->dir) - return ps; - } - - free(ps); - return NULL; -} - -void proc_close_processes(struct proc_processes *ps) -{ - if (ps && ps->dir) - closedir(ps->dir); - free(ps); -} - -void proc_processes_filter_by_name(struct proc_processes *ps, const char *name) -{ - ps->fltr_name = name; - ps->has_fltr_name = name ? 1 : 0; -} - -void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid) -{ - ps->fltr_uid = uid; - ps->has_fltr_uid = 1; -} - -int proc_next_pid(struct proc_processes *ps, pid_t *pid) -{ - struct dirent *d; - - if (!ps || !pid) - return -EINVAL; - - *pid = 0; - errno = 0; - - do { - char buf[BUFSIZ], *p; - - errno = 0; - d = readdir(ps->dir); - if (!d) - return errno ? -1 : 1; /* error or end-of-dir */ - - - if (!isdigit((unsigned char) *d->d_name)) - continue; - - /* filter out by UID */ - if (ps->has_fltr_uid) { - struct stat st; - - if (fstatat(dirfd(ps->dir), d->d_name, &st, 0)) - continue; - if (ps->fltr_uid != st.st_uid) - continue; - } - - /* filter out by NAME */ - if (ps->has_fltr_name) { - char procname[256]; - FILE *f; - - snprintf(buf, sizeof(buf), "%s/stat", d->d_name); - f = fopen_at(dirfd(ps->dir), buf, O_CLOEXEC|O_RDONLY, "r"); - if (!f) - continue; - - p = fgets(buf, sizeof(buf), f); - fclose(f); - if (!p) - continue; - - if (sscanf(buf, "%*d (%255[^)])", procname) != 1) - continue; - - /* ok, we got the process name. */ - if (strcmp(procname, ps->fltr_name) != 0) - continue; - } - - p = NULL; - errno = 0; - *pid = (pid_t) strtol(d->d_name, &p, 10); - if (errno || d->d_name == p || (p && *p)) - return errno ? -errno : -1; - - return 0; - } while (1); - - return 0; -} - -#ifdef TEST_PROGRAM_PROCUTILS - -static int test_tasks(int argc, char *argv[]) -{ - pid_t tid, pid; - struct proc_tasks *ts; - - if (argc != 2) - return EXIT_FAILURE; - - pid = strtol(argv[1], (char **) NULL, 10); - printf("PID=%d, TIDs:", pid); - - ts = proc_open_tasks(pid); - if (!ts) - err(EXIT_FAILURE, "open list of tasks failed"); - - while (proc_next_tid(ts, &tid) == 0) - printf(" %d", tid); - - printf("\n"); - proc_close_tasks(ts); - return EXIT_SUCCESS; -} - -static int test_processes(int argc, char *argv[]) -{ - pid_t pid; - struct proc_processes *ps; - - ps = proc_open_processes(); - if (!ps) - err(EXIT_FAILURE, "open list of processes failed"); - - if (argc >= 3 && strcmp(argv[1], "--name") == 0) - proc_processes_filter_by_name(ps, argv[2]); - - if (argc >= 3 && strcmp(argv[1], "--uid") == 0) - proc_processes_filter_by_uid(ps, (uid_t) atol(argv[2])); - - while (proc_next_pid(ps, &pid) == 0) - printf(" %d", pid); - - printf("\n"); - proc_close_processes(ps); - return EXIT_SUCCESS; -} - -int main(int argc, char *argv[]) -{ - if (argc < 2) { - fprintf(stderr, "usage: %1$s --tasks \n" - " %1$s --processes [---name ] [--uid ]\n", - program_invocation_short_name); - return EXIT_FAILURE; - } - - if (strcmp(argv[1], "--tasks") == 0) - return test_tasks(argc - 1, argv + 1); - if (strcmp(argv[1], "--processes") == 0) - return test_processes(argc - 1, argv + 1); - - return EXIT_FAILURE; -} -#endif /* TEST_PROGRAM_PROCUTILS */ diff --git a/utils/lib/pty-session.c b/utils/lib/pty-session.c deleted file mode 100644 index 06b2a49..0000000 --- a/utils/lib/pty-session.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * This is pseudo-terminal container for child process where parent creates a - * proxy between the current std{in,out,etrr} and the child's pty. Advantages: - * - * - child has no access to parent's terminal (e.g. su --pty) - * - parent can log all traffic between user and child's terminal (e.g. script(1)) - * - it's possible to start commands on terminal although parent has no terminal - * - * This code is in the public domain; do with it what you wish. - * - * Written by Karel Zak in Jul 2019 - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "all-io.h" -#include "ttyutils.h" -#include "pty-session.h" -#include "monotonic.h" -#include "debug.h" - -static UL_DEBUG_DEFINE_MASK(ulpty); -UL_DEBUG_DEFINE_MASKNAMES(ulpty) = UL_DEBUG_EMPTY_MASKNAMES; - -#define ULPTY_DEBUG_INIT (1 << 1) -#define ULPTY_DEBUG_SETUP (1 << 2) -#define ULPTY_DEBUG_SIG (1 << 3) -#define ULPTY_DEBUG_IO (1 << 4) -#define ULPTY_DEBUG_DONE (1 << 5) -#define ULPTY_DEBUG_ALL 0xFFFF - -#define DBG(m, x) __UL_DBG(ulpty, ULPTY_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(ulpty, ULPTY_DEBUG_, m, x) - -#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpty) -#include "debugobj.h" - -void ul_pty_init_debug(int mask) -{ - if (ulpty_debug_mask) - return; - __UL_INIT_DEBUG_FROM_ENV(ulpty, ULPTY_DEBUG_, mask, ULPTY_DEBUG); -} - -struct ul_pty *ul_new_pty(int is_stdin_tty) -{ - struct ul_pty *pty = calloc(1, sizeof(*pty)); - - if (!pty) - return NULL; - - DBG(SETUP, ul_debugobj(pty, "alloc handler")); - pty->isterm = is_stdin_tty; - pty->master = -1; - pty->slave = -1; - pty->sigfd = -1; - pty->child = (pid_t) -1; - - return pty; -} - -void ul_free_pty(struct ul_pty *pty) -{ - free(pty); -} - -void ul_pty_slave_echo(struct ul_pty *pty, int enable) -{ - assert(pty); - pty->slave_echo = enable ? 1 : 0; -} - -int ul_pty_get_delivered_signal(struct ul_pty *pty) -{ - assert(pty); - return pty->delivered_signal; -} - -struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty) -{ - assert(pty); - return &pty->callbacks; -} - -void ul_pty_set_callback_data(struct ul_pty *pty, void *data) -{ - assert(pty); - pty->callback_data = data; -} - -void ul_pty_set_child(struct ul_pty *pty, pid_t child) -{ - assert(pty); - pty->child = child; -} - -int ul_pty_get_childfd(struct ul_pty *pty) -{ - assert(pty); - return pty->master; -} - -pid_t ul_pty_get_child(struct ul_pty *pty) -{ - assert(pty); - return pty->child; -} - -/* it's active when signals are redirected to sigfd */ -int ul_pty_is_running(struct ul_pty *pty) -{ - assert(pty); - return pty->sigfd >= 0; -} - -void ul_pty_set_mainloop_time(struct ul_pty *pty, struct timeval *tv) -{ - assert(pty); - if (!tv) { - DBG(IO, ul_debugobj(pty, "mainloop time: clear")); - timerclear(&pty->next_callback_time); - } else { - pty->next_callback_time.tv_sec = tv->tv_sec; - pty->next_callback_time.tv_usec = tv->tv_usec; - DBG(IO, ul_debugobj(pty, "mainloop time: %ld.%06ld", tv->tv_sec, tv->tv_usec)); - } -} - -static void pty_signals_cleanup(struct ul_pty *pty) -{ - if (pty->sigfd != -1) - close(pty->sigfd); - pty->sigfd = -1; - - /* restore original setting */ - sigprocmask(SIG_SETMASK, &pty->orgsig, NULL); -} - -/* call me before fork() */ -int ul_pty_setup(struct ul_pty *pty) -{ - struct termios attrs; - sigset_t ourset; - int rc = 0; - - assert(pty->sigfd == -1); - - /* save the current signals setting */ - sigprocmask(0, NULL, &pty->orgsig); - - if (pty->isterm) { - DBG(SETUP, ul_debugobj(pty, "create for terminal")); - - /* original setting of the current terminal */ - if (tcgetattr(STDIN_FILENO, &pty->stdin_attrs) != 0) { - rc = -errno; - goto done; - } - - attrs = pty->stdin_attrs; - if (pty->slave_echo) - attrs.c_lflag |= ECHO; - else - attrs.c_lflag &= ~ECHO; - - ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win); - /* create master+slave */ - rc = openpty(&pty->master, &pty->slave, NULL, &attrs, &pty->win); - if (rc) - goto done; - - /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */ - cfmakeraw(&attrs); - tcsetattr(STDIN_FILENO, TCSANOW, &attrs); - } else { - DBG(SETUP, ul_debugobj(pty, "create for non-terminal")); - - rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL); - if (rc) - goto done; - - tcgetattr(pty->slave, &attrs); - - if (pty->slave_echo) - attrs.c_lflag |= ECHO; - else - attrs.c_lflag &= ~ECHO; - - tcsetattr(pty->slave, TCSANOW, &attrs); - } - - sigfillset(&ourset); - if (sigprocmask(SIG_BLOCK, &ourset, NULL)) { - rc = -errno; - goto done; - } - - sigemptyset(&ourset); - sigaddset(&ourset, SIGCHLD); - sigaddset(&ourset, SIGWINCH); - sigaddset(&ourset, SIGALRM); - sigaddset(&ourset, SIGTERM); - sigaddset(&ourset, SIGINT); - sigaddset(&ourset, SIGQUIT); - - if (pty->callbacks.flush_logs) - sigaddset(&ourset, SIGUSR1); - - if ((pty->sigfd = signalfd(-1, &ourset, SFD_CLOEXEC)) < 0) - rc = -errno; -done: - if (rc) - ul_pty_cleanup(pty); - - DBG(SETUP, ul_debugobj(pty, "pty setup done [master=%d, slave=%d, rc=%d]", - pty->master, pty->slave, rc)); - return rc; -} - -/* cleanup in parent process */ -void ul_pty_cleanup(struct ul_pty *pty) -{ - struct termios rtt; - - pty_signals_cleanup(pty); - - if (pty->master == -1 || !pty->isterm) - return; - - DBG(DONE, ul_debugobj(pty, "cleanup")); - rtt = pty->stdin_attrs; - tcsetattr(STDIN_FILENO, TCSADRAIN, &rtt); -} - -/* call me in child process */ -void ul_pty_init_slave(struct ul_pty *pty) -{ - DBG(SETUP, ul_debugobj(pty, "initialize slave")); - - setsid(); - - ioctl(pty->slave, TIOCSCTTY, 1); - close(pty->master); - - dup2(pty->slave, STDIN_FILENO); - dup2(pty->slave, STDOUT_FILENO); - dup2(pty->slave, STDERR_FILENO); - - close(pty->slave); - - if (pty->sigfd >= 0) - close(pty->sigfd); - - pty->slave = -1; - pty->master = -1; - pty->sigfd = -1; - - sigprocmask(SIG_SETMASK, &pty->orgsig, NULL); - - DBG(SETUP, ul_debugobj(pty, "... initialize slave done")); -} - -static int write_output(char *obuf, ssize_t bytes) -{ - DBG(IO, ul_debug(" writing output")); - - if (write_all(STDOUT_FILENO, obuf, bytes)) { - DBG(IO, ul_debug(" writing output *failed*")); - return -errno; - } - - return 0; -} - -static int write_to_child(struct ul_pty *pty, char *buf, size_t bufsz) -{ - return write_all(pty->master, buf, bufsz); -} - -/* - * The pty is usually faster than shell, so it's a good idea to wait until - * the previous message has been already read by shell from slave before we - * write to master. This is necessary especially for EOF situation when we can - * send EOF to master before shell is fully initialized, to workaround this - * problem we wait until slave is empty. For example: - * - * echo "date" | su --pty - * - * Unfortunately, the child (usually shell) can ignore stdin at all, so we - * don't wait forever to avoid dead locks... - * - * Note that su --pty is primarily designed for interactive sessions as it - * maintains master+slave tty stuff within the session. Use pipe to write to - * pty and assume non-interactive (tee-like) behavior is NOT well supported. - */ -void ul_pty_write_eof_to_child(struct ul_pty *pty) -{ - unsigned int tries = 0; - struct pollfd fds[] = { - { .fd = pty->slave, .events = POLLIN } - }; - char c = DEF_EOF; - - DBG(IO, ul_debugobj(pty, " waiting for empty slave")); - while (poll(fds, 1, 10) == 1 && tries < 8) { - DBG(IO, ul_debugobj(pty, " slave is not empty")); - xusleep(250000); - tries++; - } - if (tries < 8) - DBG(IO, ul_debugobj(pty, " slave is empty now")); - - DBG(IO, ul_debugobj(pty, " sending EOF to master")); - write_to_child(pty, &c, sizeof(char)); -} - -static int mainloop_callback(struct ul_pty *pty) -{ - int rc; - - if (!pty->callbacks.mainloop) - return 0; - - DBG(IO, ul_debugobj(pty, "calling mainloop callback")); - rc = pty->callbacks.mainloop(pty->callback_data); - - DBG(IO, ul_debugobj(pty, " callback done [rc=%d]", rc)); - return rc; -} - -static int handle_io(struct ul_pty *pty, int fd, int *eof) -{ - char buf[BUFSIZ]; - ssize_t bytes; - int rc = 0; - - DBG(IO, ul_debugobj(pty, " handle I/O on fd=%d", fd)); - *eof = 0; - - /* read from active FD */ - bytes = read(fd, buf, sizeof(buf)); - if (bytes < 0) { - if (errno == EAGAIN || errno == EINTR) - return 0; - return -errno; - } - - if (bytes == 0) { - *eof = 1; - return 0; - } - - /* from stdin (user) to command */ - if (fd == STDIN_FILENO) { - DBG(IO, ul_debugobj(pty, " stdin --> master %zd bytes", bytes)); - - if (write_to_child(pty, buf, bytes)) - return -errno; - - /* without sync write_output() will write both input & - * shell output that looks like double echoing */ - fdatasync(pty->master); - - /* from command (master) to stdout */ - } else if (fd == pty->master) { - DBG(IO, ul_debugobj(pty, " master --> stdout %zd bytes", bytes)); - write_output(buf, bytes); - } - - if (pty->callbacks.log_stream_activity) - rc = pty->callbacks.log_stream_activity( - pty->callback_data, fd, buf, bytes); - - return rc; -} - -void ul_pty_wait_for_child(struct ul_pty *pty) -{ - int status; - pid_t pid; - int options = 0; - - if (pty->child == (pid_t) -1) - return; - - DBG(SIG, ul_debug("waiting for child [child=%d]", (int) pty->child)); - - if (ul_pty_is_running(pty)) { - /* wait for specific child */ - options = WNOHANG; - for (;;) { - pid = waitpid(pty->child, &status, options); - DBG(SIG, ul_debug(" waitpid done [rc=%d]", (int) pid)); - if (pid != (pid_t) - 1) { - if (pty->callbacks.child_die) - pty->callbacks.child_die( - pty->callback_data, - pty->child, status); - ul_pty_set_child(pty, (pid_t) -1); - } else - break; - } - } else { - /* final wait */ - while ((pid = wait3(&status, options, NULL)) > 0) { - DBG(SIG, ul_debug(" wait3 done [rc=%d]", (int) pid)); - if (pid == pty->child) { - if (pty->callbacks.child_die) - pty->callbacks.child_die( - pty->callback_data, - pty->child, status); - ul_pty_set_child(pty, (pid_t) -1); - } - } - } -} - -static int handle_signal(struct ul_pty *pty, int fd) -{ - struct signalfd_siginfo info; - ssize_t bytes; - int rc = 0; - - DBG(SIG, ul_debugobj(pty, " handle signal on fd=%d", fd)); - - bytes = read(fd, &info, sizeof(info)); - if (bytes != sizeof(info)) { - if (bytes < 0 && (errno == EAGAIN || errno == EINTR)) - return 0; - return -errno; - } - - switch (info.ssi_signo) { - case SIGCHLD: - DBG(SIG, ul_debugobj(pty, " get signal SIGCHLD")); - - if (info.ssi_code == CLD_EXITED - || info.ssi_code == CLD_KILLED - || info.ssi_code == CLD_DUMPED) { - - if (pty->callbacks.child_wait) - pty->callbacks.child_wait(pty->callback_data, - pty->child); - else - ul_pty_wait_for_child(pty); - - } else if (info.ssi_status == SIGSTOP && pty->child > 0) - pty->callbacks.child_sigstop(pty->callback_data, - pty->child); - - if (pty->child <= 0) { - DBG(SIG, ul_debugobj(pty, " no child, setting leaving timeout")); - pty->poll_timeout = 10; - timerclear(&pty->next_callback_time); - } - return 0; - case SIGWINCH: - DBG(SIG, ul_debugobj(pty, " get signal SIGWINCH")); - if (pty->isterm) { - ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win); - ioctl(pty->slave, TIOCSWINSZ, (char *)&pty->win); - - if (pty->callbacks.log_signal) - rc = pty->callbacks.log_signal(pty->callback_data, - &info, (void *) &pty->win); - } - break; - case SIGTERM: - /* fallthrough */ - case SIGINT: - /* fallthrough */ - case SIGQUIT: - DBG(SIG, ul_debugobj(pty, " get signal SIG{TERM,INT,QUIT}")); - pty->delivered_signal = info.ssi_signo; - /* Child termination is going to generate SIGCHLD (see above) */ - if (pty->child > 0) - kill(pty->child, SIGTERM); - - if (pty->callbacks.log_signal) - rc = pty->callbacks.log_signal(pty->callback_data, - &info, (void *) &pty->win); - break; - case SIGUSR1: - DBG(SIG, ul_debugobj(pty, " get signal SIGUSR1")); - if (pty->callbacks.flush_logs) - rc = pty->callbacks.flush_logs(pty->callback_data); - break; - default: - abort(); - } - - return rc; -} - -/* loop in parent */ -int ul_pty_proxy_master(struct ul_pty *pty) -{ - int rc = 0, ret, eof = 0; - enum { - POLLFD_SIGNAL = 0, - POLLFD_MASTER, - POLLFD_STDIN - - }; - struct pollfd pfd[] = { - [POLLFD_SIGNAL] = { .fd = -1, .events = POLLIN | POLLERR | POLLHUP }, - [POLLFD_MASTER] = { .fd = pty->master, .events = POLLIN | POLLERR | POLLHUP }, - [POLLFD_STDIN] = { .fd = STDIN_FILENO, .events = POLLIN | POLLERR | POLLHUP } - }; - - /* We use signalfd, and standard signals by handlers are completely blocked */ - assert(pty->sigfd >= 0); - - pfd[POLLFD_SIGNAL].fd = pty->sigfd; - pty->poll_timeout = -1; - - while (!pty->delivered_signal) { - size_t i; - int errsv, timeout; - - DBG(IO, ul_debugobj(pty, "--poll() loop--")); - - /* note, callback usually updates @next_callback_time */ - if (timerisset(&pty->next_callback_time)) { - struct timeval now; - - DBG(IO, ul_debugobj(pty, " callback requested")); - gettime_monotonic(&now); - if (timercmp(&now, &pty->next_callback_time, >)) { - rc = mainloop_callback(pty); - if (rc) - break; - } - } - - /* set timeout */ - if (timerisset(&pty->next_callback_time)) { - struct timeval now, rest; - - gettime_monotonic(&now); - timersub(&pty->next_callback_time, &now, &rest); - timeout = (rest.tv_sec * 1000) + (rest.tv_usec / 1000); - } else - timeout = pty->poll_timeout; - - /* wait for input, signal or timeout */ - DBG(IO, ul_debugobj(pty, "calling poll() [timeout=%dms]", timeout)); - ret = poll(pfd, ARRAY_SIZE(pfd), timeout); - - errsv = errno; - DBG(IO, ul_debugobj(pty, "poll() rc=%d", ret)); - - /* error */ - if (ret < 0) { - if (errsv == EAGAIN) - continue; - rc = -errno; - break; - } - - /* timeout */ - if (ret == 0) { - if (timerisset(&pty->next_callback_time)) { - rc = mainloop_callback(pty); - if (rc == 0) - continue; - } else - rc = 0; - - DBG(IO, ul_debugobj(pty, "leaving poll() loop [timeout=%d, rc=%d]", timeout, rc)); - break; - } - /* event */ - for (i = 0; i < ARRAY_SIZE(pfd); i++) { - rc = 0; - - if (pfd[i].revents == 0) - continue; - - DBG(IO, ul_debugobj(pty, " active pfd[%s].fd=%d %s %s %s %s", - i == POLLFD_STDIN ? "stdin" : - i == POLLFD_MASTER ? "master" : - i == POLLFD_SIGNAL ? "signal" : "???", - pfd[i].fd, - pfd[i].revents & POLLIN ? "POLLIN" : "", - pfd[i].revents & POLLHUP ? "POLLHUP" : "", - pfd[i].revents & POLLERR ? "POLLERR" : "", - pfd[i].revents & POLLNVAL ? "POLLNVAL" : "")); - - switch (i) { - case POLLFD_STDIN: - case POLLFD_MASTER: - /* data */ - if (pfd[i].revents & POLLIN) - rc = handle_io(pty, pfd[i].fd, &eof); - /* EOF maybe detected in two ways; they are as follows: - * A) poll() return POLLHUP event after close() - * B) read() returns 0 (no data) - * - * POLLNVAL means that fd is closed. - */ - if ((pfd[i].revents & POLLHUP) || (pfd[i].revents & POLLNVAL) || eof) { - DBG(IO, ul_debugobj(pty, " ignore FD")); - pfd[i].fd = -1; - if (i == POLLFD_STDIN) { - ul_pty_write_eof_to_child(pty); - DBG(IO, ul_debugobj(pty, " ignore STDIN")); - } - } - continue; - case POLLFD_SIGNAL: - rc = handle_signal(pty, pfd[i].fd); - break; - } - if (rc) - break; - } - } - - pty_signals_cleanup(pty); - - DBG(IO, ul_debug("poll() done [signal=%d, rc=%d]", pty->delivered_signal, rc)); - return rc; -} - -#ifdef TEST_PROGRAM_PTY -/* - * $ make test_pty - * $ ./test_pty - * - * ... and see for example tty(1) or "ps afu" - */ -static void child_sigstop(void *data __attribute__((__unused__)), pid_t child) -{ - kill(getpid(), SIGSTOP); - kill(child, SIGCONT); -} - -int main(int argc, char *argv[]) -{ - struct ul_pty_callbacks *cb; - const char *shell, *command = NULL, *shname = NULL; - int caught_signal = 0; - pid_t child; - struct ul_pty *pty; - - shell = getenv("SHELL"); - if (shell == NULL) - shell = _PATH_BSHELL; - if (argc == 2) - command = argv[1]; - - ul_pty_init_debug(0); - - pty = ul_new_pty(isatty(STDIN_FILENO)); - if (!pty) - err(EXIT_FAILURE, "failed to allocate PTY handler"); - - cb = ul_pty_get_callbacks(pty); - cb->child_sigstop = child_sigstop; - - if (ul_pty_setup(pty)) - err(EXIT_FAILURE, "failed to create pseudo-terminal"); - - fflush(stdout); /* ??? */ - - switch ((int) (child = fork())) { - case -1: /* error */ - ul_pty_cleanup(pty); - err(EXIT_FAILURE, "cannot create child process"); - break; - - case 0: /* child */ - ul_pty_init_slave(pty); - - signal(SIGTERM, SIG_DFL); /* because /etc/csh.login */ - - shname = strrchr(shell, '/'); - shname = shname ? shname + 1 : shell; - - if (command) - execl(shell, shname, "-c", command, NULL); - else - execl(shell, shname, "-i", NULL); - err(EXIT_FAILURE, "failed to execute %s", shell); - break; - - default: - break; - } - - /* parent */ - ul_pty_set_child(pty, child); - - /* this is the main loop */ - ul_pty_proxy_master(pty); - - /* all done; cleanup and kill */ - caught_signal = ul_pty_get_delivered_signal(pty); - - if (!caught_signal && ul_pty_get_child(pty) != (pid_t)-1) - ul_pty_wait_for_child(pty); /* final wait */ - - if (caught_signal && ul_pty_get_child(pty) != (pid_t)-1) { - fprintf(stderr, "\nSession terminated, killing shell..."); - kill(child, SIGTERM); - sleep(2); - kill(child, SIGKILL); - fprintf(stderr, " ...killed.\n"); - } - - ul_pty_cleanup(pty); - ul_free_pty(pty); - return EXIT_SUCCESS; -} - -#endif /* TEST_PROGRAM */ - diff --git a/utils/lib/pwdutils.c b/utils/lib/pwdutils.c deleted file mode 100644 index d5f4d2e..0000000 --- a/utils/lib/pwdutils.c +++ /dev/null @@ -1,156 +0,0 @@ -#include - -#include "c.h" -#include "pwdutils.h" -#include "xalloc.h" - -/* Returns allocated passwd and allocated pwdbuf to store passwd strings - * fields. In case of error returns NULL and set errno, for unknown user set - * errno to EINVAL - */ -struct passwd *xgetpwnam(const char *username, char **pwdbuf) -{ - struct passwd *pwd = NULL, *res = NULL; - int rc; - - if (!pwdbuf || !username) - return NULL; - - *pwdbuf = xmalloc(UL_GETPW_BUFSIZ); - pwd = xcalloc(1, sizeof(struct passwd)); - - errno = 0; - rc = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); - if (rc != 0) { - errno = rc; - goto failed; - } - if (!res) { - errno = EINVAL; - goto failed; - } - return pwd; -failed: - free(pwd); - free(*pwdbuf); - return NULL; -} - -/* Returns allocated group and allocated grpbuf to store group strings - * fields. In case of error returns NULL and set errno, for unknown group set - * errno to EINVAL - */ -struct group *xgetgrnam(const char *groupname, char **grpbuf) -{ - struct group *grp = NULL, *res = NULL; - int rc; - - if (!grpbuf || !groupname) - return NULL; - - *grpbuf = xmalloc(UL_GETPW_BUFSIZ); - grp = xcalloc(1, sizeof(struct group)); - - errno = 0; - rc = getgrnam_r(groupname, grp, *grpbuf, UL_GETPW_BUFSIZ, &res); - if (rc != 0) { - errno = rc; - goto failed; - } - if (!res) { - errno = EINVAL; - goto failed; - } - return grp; -failed: - free(grp); - free(*grpbuf); - return NULL; -} - -struct passwd *xgetpwuid(uid_t uid, char **pwdbuf) -{ - struct passwd *pwd = NULL, *res = NULL; - int rc; - - if (!pwdbuf) - return NULL; - - *pwdbuf = xmalloc(UL_GETPW_BUFSIZ); - pwd = xcalloc(1, sizeof(struct passwd)); - - errno = 0; - rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); - if (rc != 0) { - errno = rc; - goto failed; - } - if (!res) { - errno = EINVAL; - goto failed; - } - return pwd; -failed: - free(pwd); - free(*pwdbuf); - return NULL; -} - -char *xgetlogin(void) -{ - struct passwd *pw = NULL; - uid_t ruid; - char *user; - - user = getlogin(); - if (user) - return xstrdup(user); - - /* GNU Hurd implementation has an extension where a process can exist in a - * non-conforming environment, and thus be outside the realms of POSIX - * process identifiers; on this platform, getuid() fails with a status of - * (uid_t)(-1) and sets errno if a program is run from a non-conforming - * environment. - * - * http://austingroupbugs.net/view.php?id=511 - */ - errno = 0; - ruid = getuid(); - - if (errno == 0) - pw = getpwuid(ruid); - if (pw && pw->pw_name && *pw->pw_name) - return xstrdup(pw->pw_name); - - return NULL; -} - -#ifdef TEST_PROGRAM -int main(int argc, char *argv[]) -{ - char *buf = NULL; - struct passwd *pwd = NULL; - - if (argc != 2) { - fprintf(stderr, "usage: %s \n", argv[0]); - return EXIT_FAILURE; - } - - pwd = xgetpwnam(argv[1], &buf); - if (!pwd) - err(EXIT_FAILURE, "failed to get %s pwd entry", argv[1]); - - printf("Username: %s\n", pwd->pw_name); - printf("UID: %d\n", pwd->pw_uid); - printf("HOME: %s\n", pwd->pw_dir); - printf("GECO: %s\n", pwd->pw_gecos); - - free(pwd); - free(buf); - - printf("Current: %s\n", (buf = xgetlogin())); - free(buf); - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/utils/lib/randutils.c b/utils/lib/randutils.c deleted file mode 100644 index bd2a8f6..0000000 --- a/utils/lib/randutils.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * General purpose random utilities. Based on libuuid code. - * - * This code is free software; you can redistribute it and/or modify it under - * the terms of the Modified BSD License. The complete text of the license is - * available in the Documentation/licenses/COPYING.BSD-3-Clause file. - */ -#include -#include -#include -#include -#include -#include - -#include - -#include "c.h" -#include "randutils.h" -#include "nls.h" - -#ifdef HAVE_TLS -#define THREAD_LOCAL static __thread -#else -#define THREAD_LOCAL static -#endif - -#ifdef HAVE_GETRANDOM -# include -#elif defined (__linux__) -# if !defined(SYS_getrandom) && defined(__NR_getrandom) - /* usable kernel-headers, but old glibc-headers */ -# define SYS_getrandom __NR_getrandom -# endif -#endif - -#if !defined(HAVE_GETRANDOM) && defined(SYS_getrandom) -/* libc without function, but we have syscal */ -#define GRND_NONBLOCK 0x01 -#define GRND_RANDOM 0x02 -static int getrandom(void *buf, size_t buflen, unsigned int flags) -{ - return (syscall(SYS_getrandom, buf, buflen, flags)); -} -# define HAVE_GETRANDOM -#endif - -#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) -#define DO_JRAND_MIX -THREAD_LOCAL unsigned short ul_jrand_seed[3]; -#endif - -int rand_get_number(int low_n, int high_n) -{ - return rand() % (high_n - low_n + 1) + low_n; -} - -static void crank_random(void) -{ - int i; - struct timeval tv; - unsigned int n_pid, n_uid; - - gettimeofday(&tv, NULL); - n_pid = getpid(); - n_uid = getuid(); - srand((n_pid << 16) ^ n_uid ^ tv.tv_sec ^ tv.tv_usec); - -#ifdef DO_JRAND_MIX - ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); - ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); - ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; -#endif - /* Crank the random number generator a few times */ - gettimeofday(&tv, NULL); - for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) - rand(); -} - -int random_get_fd(void) -{ - int i, fd; - - fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); - if (fd == -1) - fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd >= 0) { - i = fcntl(fd, F_GETFD); - if (i >= 0) - fcntl(fd, F_SETFD, i | FD_CLOEXEC); - } - crank_random(); - return fd; -} - -/* - * Generate a stream of random nbytes into buf. - * Use /dev/urandom if possible, and if not, - * use glibc pseudo-random functions. - */ -#define UL_RAND_READ_ATTEMPTS 8 -#define UL_RAND_READ_DELAY 125000 /* microseconds */ - -void random_get_bytes(void *buf, size_t nbytes) -{ - unsigned char *cp = (unsigned char *)buf; - size_t i, n = nbytes; - int lose_counter = 0; - -#ifdef HAVE_GETRANDOM - while (n > 0) { - int x; - - errno = 0; - x = getrandom(cp, n, GRND_NONBLOCK); - if (x > 0) { /* success */ - n -= x; - cp += x; - lose_counter = 0; - - } else if (errno == ENOSYS) { /* kernel without getrandom() */ - break; - - } else if (errno == EAGAIN && lose_counter < UL_RAND_READ_ATTEMPTS) { - xusleep(UL_RAND_READ_DELAY); /* no entropy, wait and try again */ - lose_counter++; - } else - break; - } - - if (errno == ENOSYS) -#endif - /* - * We've been built against headers that support getrandom, but the - * running kernel does not. Fallback to reading from /dev/{u,}random - * as before - */ - { - int fd = random_get_fd(); - - lose_counter = 0; - if (fd >= 0) { - while (n > 0) { - ssize_t x = read(fd, cp, n); - if (x <= 0) { - if (lose_counter++ > UL_RAND_READ_ATTEMPTS) - break; - xusleep(UL_RAND_READ_DELAY); - continue; - } - n -= x; - cp += x; - lose_counter = 0; - } - - close(fd); - } - } - /* - * We do this all the time, but this is the only source of - * randomness if /dev/random/urandom is out to lunch. - */ - crank_random(); - for (cp = buf, i = 0; i < nbytes; i++) - *cp++ ^= (rand() >> 7) & 0xFF; - -#ifdef DO_JRAND_MIX - { - unsigned short tmp_seed[3]; - - memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed)); - ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid); - for (cp = buf, i = 0; i < nbytes; i++) - *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; - memcpy(ul_jrand_seed, tmp_seed, - sizeof(ul_jrand_seed)-sizeof(unsigned short)); - } -#endif -} - - -/* - * Tell source of randomness. - */ -const char *random_tell_source(void) -{ -#ifdef HAVE_GETRANDOM - return _("getrandom() function"); -#else - size_t i; - static const char *random_sources[] = { - "/dev/urandom", - "/dev/random" - }; - - for (i = 0; i < ARRAY_SIZE(random_sources); i++) { - if (!access(random_sources[i], R_OK)) - return random_sources[i]; - } -#endif - return _("libc pseudo-random functions"); -} - -#ifdef TEST_PROGRAM_RANDUTILS -#include - -int main(int argc, char *argv[]) -{ - size_t i, n; - int64_t *vp, v; - char *buf; - size_t bufsz; - - n = argc == 1 ? 16 : atoi(argv[1]); - - printf("Multiple random calls:\n"); - for (i = 0; i < n; i++) { - random_get_bytes(&v, sizeof(v)); - printf("#%02zu: %25"PRIu64"\n", i, v); - } - - - printf("One random call:\n"); - bufsz = n * sizeof(*vp); - buf = malloc(bufsz); - if (!buf) - err(EXIT_FAILURE, "failed to allocate buffer"); - - random_get_bytes(buf, bufsz); - for (i = 0; i < n; i++) { - vp = (int64_t *) (buf + (i * sizeof(*vp))); - printf("#%02zu: %25"PRIu64"\n", i, *vp); - } - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM_RANDUTILS */ diff --git a/utils/lib/setproctitle.c b/utils/lib/setproctitle.c deleted file mode 100644 index 7168e46..0000000 --- a/utils/lib/setproctitle.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * set process title for ps (from sendmail) - * - * Clobbers argv of our main procedure so ps(1) will display the title. - */ -#include -#include -#include -#include - -#include "setproctitle.h" - -#ifndef SPT_BUFSIZE -# define SPT_BUFSIZE 2048 -#endif - -extern char **environ; - -static char **argv0; -static size_t argv_lth; - -void initproctitle (int argc, char **argv) -{ - int i; - char **envp = environ; - - /* - * Move the environment so we can reuse the memory. - * (Code borrowed from sendmail.) - * WARNING: ugly assumptions on memory layout here; - * if this ever causes problems, #undef DO_PS_FIDDLING - */ - for (i = 0; envp[i] != NULL; i++) - continue; - - environ = malloc(sizeof(char *) * (i + 1)); - if (environ == NULL) - return; - - for (i = 0; envp[i] != NULL; i++) - if ((environ[i] = strdup(envp[i])) == NULL) - return; - environ[i] = NULL; - - if (i > 0) - argv_lth = envp[i-1] + strlen(envp[i-1]) - argv[0]; - else - argv_lth = argv[argc-1] + strlen(argv[argc-1]) - argv[0]; - if (argv_lth > 1) - argv0 = argv; -} - -void setproctitle (const char *prog, const char *txt) -{ - size_t i; - char buf[SPT_BUFSIZE]; - - if (!argv0) - return; - - if (strlen(prog) + strlen(txt) + 5 > SPT_BUFSIZE) - return; - - sprintf(buf, "%s -- %s", prog, txt); - - i = strlen(buf); - if (i > argv_lth - 2) { - i = argv_lth - 2; - buf[i] = '\0'; - } - memset(argv0[0], '\0', argv_lth); /* clear the memory area */ - strcpy(argv0[0], buf); - - argv0[1] = NULL; -} diff --git a/utils/lib/sha1.c b/utils/lib/sha1.c deleted file mode 100644 index 22d33b3..0000000 --- a/utils/lib/sha1.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * SHA-1 in C by Steve Reid - * 100% Public Domain - * - * Test Vectors (from FIPS PUB 180-1) - * 1) "abc": A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - * 2) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq": 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - * 3) A million repetitions of "a": 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F - */ - -#define UL_SHA1HANDSOFF - -#include -#include -#include - -#include "sha1.h" - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -#ifdef WORDS_BIGENDIAN -# define blk0(i) block->l[i] -#else -# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#endif - -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void ul_SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) -{ - uint32_t a, b, c, d, e; - - typedef union { - unsigned char c[64]; - uint32_t l[16]; - } CHAR64LONG16; - -#ifdef UL_SHA1HANDSOFF - CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ - CHAR64LONG16 *block = (const CHAR64LONG16 *)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a, b, c, d, e, 0); - R0(e, a, b, c, d, 1); - R0(d, e, a, b, c, 2); - R0(c, d, e, a, b, 3); - R0(b, c, d, e, a, 4); - R0(a, b, c, d, e, 5); - R0(e, a, b, c, d, 6); - R0(d, e, a, b, c, 7); - R0(c, d, e, a, b, 8); - R0(b, c, d, e, a, 9); - R0(a, b, c, d, e, 10); - R0(e, a, b, c, d, 11); - R0(d, e, a, b, c, 12); - R0(c, d, e, a, b, 13); - R0(b, c, d, e, a, 14); - R0(a, b, c, d, e, 15); - R1(e, a, b, c, d, 16); - R1(d, e, a, b, c, 17); - R1(c, d, e, a, b, 18); - R1(b, c, d, e, a, 19); - R2(a, b, c, d, e, 20); - R2(e, a, b, c, d, 21); - R2(d, e, a, b, c, 22); - R2(c, d, e, a, b, 23); - R2(b, c, d, e, a, 24); - R2(a, b, c, d, e, 25); - R2(e, a, b, c, d, 26); - R2(d, e, a, b, c, 27); - R2(c, d, e, a, b, 28); - R2(b, c, d, e, a, 29); - R2(a, b, c, d, e, 30); - R2(e, a, b, c, d, 31); - R2(d, e, a, b, c, 32); - R2(c, d, e, a, b, 33); - R2(b, c, d, e, a, 34); - R2(a, b, c, d, e, 35); - R2(e, a, b, c, d, 36); - R2(d, e, a, b, c, 37); - R2(c, d, e, a, b, 38); - R2(b, c, d, e, a, 39); - R3(a, b, c, d, e, 40); - R3(e, a, b, c, d, 41); - R3(d, e, a, b, c, 42); - R3(c, d, e, a, b, 43); - R3(b, c, d, e, a, 44); - R3(a, b, c, d, e, 45); - R3(e, a, b, c, d, 46); - R3(d, e, a, b, c, 47); - R3(c, d, e, a, b, 48); - R3(b, c, d, e, a, 49); - R3(a, b, c, d, e, 50); - R3(e, a, b, c, d, 51); - R3(d, e, a, b, c, 52); - R3(c, d, e, a, b, 53); - R3(b, c, d, e, a, 54); - R3(a, b, c, d, e, 55); - R3(e, a, b, c, d, 56); - R3(d, e, a, b, c, 57); - R3(c, d, e, a, b, 58); - R3(b, c, d, e, a, 59); - R4(a, b, c, d, e, 60); - R4(e, a, b, c, d, 61); - R4(d, e, a, b, c, 62); - R4(c, d, e, a, b, 63); - R4(b, c, d, e, a, 64); - R4(a, b, c, d, e, 65); - R4(e, a, b, c, d, 66); - R4(d, e, a, b, c, 67); - R4(c, d, e, a, b, 68); - R4(b, c, d, e, a, 69); - R4(a, b, c, d, e, 70); - R4(e, a, b, c, d, 71); - R4(d, e, a, b, c, 72); - R4(c, d, e, a, b, 73); - R4(b, c, d, e, a, 74); - R4(a, b, c, d, e, 75); - R4(e, a, b, c, d, 76); - R4(d, e, a, b, c, 77); - R4(c, d, e, a, b, 78); - R4(b, c, d, e, a, 79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef UL_SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - -/* SHA1Init - Initialize new context */ - -void ul_SHA1Init(UL_SHA1_CTX *context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - -/* Run your data through this. */ - -void ul_SHA1Update(UL_SHA1_CTX *context, const unsigned char *data, uint32_t len) -{ - uint32_t i; - - uint32_t j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len >> 29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64 - j)); - ul_SHA1Transform(context->state, context->buffer); - for (; i + 63 < len; i += 64) { - ul_SHA1Transform(context->state, &data[i]); - } - j = 0; - } else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - -/* Add padding and return the message digest. */ - -void ul_SHA1Final(unsigned char digest[20], UL_SHA1_CTX *context) -{ - unsigned i; - - unsigned char finalcount[8]; - - unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) { - uint32_t t = context->count[i]; - - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char)t} -#else - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ - } -#endif - c = 0200; - ul_SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - ul_SHA1Update(context, &c, 1); - } - ul_SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} - -void ul_SHA1(char *hash_out, const char *str, unsigned len) -{ - UL_SHA1_CTX ctx; - unsigned int ii; - - ul_SHA1Init(&ctx); - for (ii = 0; ii < len; ii += 1) - ul_SHA1Update(&ctx, (const unsigned char *)str + ii, 1); - ul_SHA1Final((unsigned char *)hash_out, &ctx); - hash_out[20] = '\0'; -} diff --git a/utils/lib/signames.c b/utils/lib/signames.c deleted file mode 100644 index 316eec5..0000000 --- a/utils/lib/signames.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 1988, 1993, 1994, 2017 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * 2017-10-14 Niklas Hambüchen - * - Extracted signal names mapping from kill.c - * - * Copyright (C) 2014 Sami Kerola - * Copyright (C) 2014 Karel Zak - * Copyright (C) 2017 Niklas Hambüchen - */ - -#include /* for isdigit() */ -#include -#include -#include -#include - -#include "c.h" -#include "strutils.h" -#include "signames.h" - -static const struct ul_signal_name { - const char *name; - int val; -} ul_signames[] = { - /* POSIX signals */ - { "HUP", SIGHUP }, /* 1 */ - { "INT", SIGINT }, /* 2 */ - { "QUIT", SIGQUIT }, /* 3 */ - { "ILL", SIGILL }, /* 4 */ -#ifdef SIGTRAP - { "TRAP", SIGTRAP }, /* 5 */ -#endif - { "ABRT", SIGABRT }, /* 6 */ -#ifdef SIGIOT - { "IOT", SIGIOT }, /* 6, same as SIGABRT */ -#endif -#ifdef SIGEMT - { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */ -#endif -#ifdef SIGBUS - { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */ -#endif - { "FPE", SIGFPE }, /* 8 */ - { "KILL", SIGKILL }, /* 9 */ - { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */ - { "SEGV", SIGSEGV }, /* 11 */ - { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */ - { "PIPE", SIGPIPE }, /* 13 */ - { "ALRM", SIGALRM }, /* 14 */ - { "TERM", SIGTERM }, /* 15 */ -#ifdef SIGSTKFLT - { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */ -#endif - { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */ -#ifdef SIGCLD - { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */ -#endif - { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */ - { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */ - { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */ - { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */ - { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */ -#ifdef SIGURG - { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */ -#endif -#ifdef SIGXCPU - { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */ -#endif -#ifdef SIGXFSZ - { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */ -#endif -#ifdef SIGVTALRM - { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */ -#endif -#ifdef SIGPROF - { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */ -#endif -#ifdef SIGWINCH - { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */ -#endif -#ifdef SIGIO - { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */ -#endif -#ifdef SIGPOLL - { "POLL", SIGPOLL }, /* same as SIGIO */ -#endif -#ifdef SIGINFO - { "INFO", SIGINFO }, /* 29 (alpha) */ -#endif -#ifdef SIGLOST - { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */ -#endif -#ifdef SIGPWR - { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */ -#endif -#ifdef SIGUNUSED - { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */ -#endif -#ifdef SIGSYS - { "SYS", SIGSYS }, /* 31 (mips,alpha,sparc*) */ -#endif -}; - -#ifdef SIGRTMIN -static int rtsig_to_signum(const char *sig) -{ - int num, maxi = 0; - char *ep = NULL; - - if (strncasecmp(sig, "min+", 4) == 0) - sig += 4; - else if (strncasecmp(sig, "max-", 4) == 0) { - sig += 4; - maxi = 1; - } - if (!isdigit(*sig)) - return -1; - errno = 0; - num = strtol(sig, &ep, 10); - if (!ep || sig == ep || errno || num < 0) - return -1; - num = maxi ? SIGRTMAX - num : SIGRTMIN + num; - if (num < SIGRTMIN || SIGRTMAX < num) - return -1; - return num; -} -#endif - -int signame_to_signum(const char *sig) -{ - size_t n; - - if (!strncasecmp(sig, "sig", 3)) - sig += 3; -#ifdef SIGRTMIN - /* RT signals */ - if (!strncasecmp(sig, "rt", 2)) - return rtsig_to_signum(sig + 2); -#endif - /* Normal signals */ - for (n = 0; n < ARRAY_SIZE(ul_signames); n++) { - if (!strcasecmp(ul_signames[n].name, sig)) - return ul_signames[n].val; - } - return -1; -} - -const char *signum_to_signame(int signum) -{ - size_t n; - - for (n = 0; n < ARRAY_SIZE(ul_signames); n++) { - if (ul_signames[n].val == signum) { - return ul_signames[n].name; - } - } - - return NULL; -} - -int get_signame_by_idx(size_t idx, const char **signame, int *signum) -{ - if (idx >= ARRAY_SIZE(ul_signames)) - return -1; - - if (signame) - *signame = ul_signames[idx].name; - if (signum) - *signum = ul_signames[idx].val; - return 0; - -} - diff --git a/utils/lib/strutils.c b/utils/lib/strutils.c deleted file mode 100644 index 304f314..0000000 --- a/utils/lib/strutils.c +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * Copyright (C) 2010 Karel Zak - * Copyright (C) 2010 Davidlohr Bueso - * - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "nls.h" -#include "strutils.h" -#include "bitops.h" -#include "pathnames.h" - -static int STRTOXX_EXIT_CODE = EXIT_FAILURE; - -void strutils_set_exitcode(int ex) { - STRTOXX_EXIT_CODE = ex; -} - -static int do_scale_by_power (uintmax_t *x, int base, int power) -{ - while (power--) { - if (UINTMAX_MAX / base < *x) - return -ERANGE; - *x *= base; - } - return 0; -} - -/* - * strtosize() - convert string to size (uintmax_t). - * - * Supported suffixes: - * - * XiB or X for 2^N - * where X = {K,M,G,T,P,E,Z,Y} - * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only) - * for example: - * 10KiB = 10240 - * 10K = 10240 - * - * XB for 10^N - * where X = {K,M,G,T,P,E,Z,Y} - * for example: - * 10KB = 10000 - * - * The optional 'power' variable returns number associated with used suffix - * {K,M,G,T,P,E,Z,Y} = {1,2,3,4,5,6,7,8}. - * - * The function also supports decimal point, for example: - * 0.5MB = 500000 - * 0.5MiB = 512000 - * - * Note that the function does not accept numbers with '-' (negative sign) - * prefix. - */ -int parse_size(const char *str, uintmax_t *res, int *power) -{ - const char *p; - char *end; - uintmax_t x, frac = 0; - int base = 1024, rc = 0, pwr = 0, frac_zeros = 0; - - static const char *suf = "KMGTPEZY"; - static const char *suf2 = "kmgtpezy"; - const char *sp; - - *res = 0; - - if (!str || !*str) { - rc = -EINVAL; - goto err; - } - - /* Only positive numbers are acceptable - * - * Note that this check is not perfect, it would be better to - * use lconv->negative_sign. But coreutils use the same solution, - * so it's probably good enough... - */ - p = str; - while (isspace((unsigned char) *p)) - p++; - if (*p == '-') { - rc = -EINVAL; - goto err; - } - - errno = 0, end = NULL; - x = strtoumax(str, &end, 0); - - if (end == str || - (errno != 0 && (x == UINTMAX_MAX || x == 0))) { - rc = errno ? -errno : -EINVAL; - goto err; - } - if (!end || !*end) - goto done; /* without suffix */ - p = end; - - /* - * Check size suffixes - */ -check_suffix: - if (*(p + 1) == 'i' && (*(p + 2) == 'B' || *(p + 2) == 'b') && !*(p + 3)) - base = 1024; /* XiB, 2^N */ - else if ((*(p + 1) == 'B' || *(p + 1) == 'b') && !*(p + 2)) - base = 1000; /* XB, 10^N */ - else if (*(p + 1)) { - struct lconv const *l = localeconv(); - const char *dp = l ? l->decimal_point : NULL; - size_t dpsz = dp ? strlen(dp) : 0; - - if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) { - const char *fstr = p + dpsz; - - for (p = fstr; *p == '0'; p++) - frac_zeros++; - fstr = p; - if (isdigit(*fstr)) { - errno = 0, end = NULL; - frac = strtoumax(fstr, &end, 0); - if (end == fstr || - (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) { - rc = errno ? -errno : -EINVAL; - goto err; - } - } else - end = (char *) p; - - if (frac && (!end || !*end)) { - rc = -EINVAL; - goto err; /* without suffix, but with frac */ - } - p = end; - goto check_suffix; - } - rc = -EINVAL; - goto err; /* unexpected suffix */ - } - - sp = strchr(suf, *p); - if (sp) - pwr = (sp - suf) + 1; - else { - sp = strchr(suf2, *p); - if (sp) - pwr = (sp - suf2) + 1; - else { - rc = -EINVAL; - goto err; - } - } - - rc = do_scale_by_power(&x, base, pwr); - if (power) - *power = pwr; - if (frac && pwr) { - int i; - uintmax_t frac_div = 10, frac_poz = 1, frac_base = 1; - - /* mega, giga, ... */ - do_scale_by_power(&frac_base, base, pwr); - - /* maximal divisor for last digit (e.g. for 0.05 is - * frac_div=100, for 0.054 is frac_div=1000, etc.) - * - * Reduce frac if too large. - */ - while (frac_div < frac) { - if (frac_div <= UINTMAX_MAX/10) - frac_div *= 10; - else - frac /= 10; - } - - /* 'frac' is without zeros (5 means 0.5 as well as 0.05) */ - for (i = 0; i < frac_zeros; i++) { - if (frac_div <= UINTMAX_MAX/10) - frac_div *= 10; - else - frac /= 10; - } - - /* - * Go backwardly from last digit and add to result what the - * digit represents in the frac_base. For example 0.25G - * - * 5 means 1GiB / (100/5) - * 2 means 1GiB / (10/2) - */ - do { - unsigned int seg = frac % 10; /* last digit of the frac */ - uintmax_t seg_div = frac_div / frac_poz; /* what represents the segment 1000, 100, .. */ - - frac /= 10; /* remove last digit from frac */ - frac_poz *= 10; - - if (seg && seg_div / seg) - x += frac_base / (seg_div / seg); - } while (frac); - } -done: - *res = x; -err: - if (rc < 0) - errno = -rc; - return rc; -} - -int strtosize(const char *str, uintmax_t *res) -{ - return parse_size(str, res, NULL); -} - -int isdigit_strend(const char *str, const char **end) -{ - const char *p; - - for (p = str; p && *p && isdigit((unsigned char) *p); p++); - - if (end) - *end = p; - return p && p > str && !*p; -} - -int isxdigit_strend(const char *str, const char **end) -{ - const char *p; - - for (p = str; p && *p && isxdigit((unsigned char) *p); p++); - - if (end) - *end = p; - - return p && p > str && !*p; -} - -/* - * parse_switch(argv[i], "on", "off", "yes", "no", NULL); - */ -int parse_switch(const char *arg, const char *errmesg, ...) -{ - const char *a, *b; - va_list ap; - - va_start(ap, errmesg); - do { - a = va_arg(ap, char *); - if (!a) - break; - b = va_arg(ap, char *); - if (!b) - break; - - if (strcmp(arg, a) == 0) { - va_end(ap); - return 1; - } - - if (strcmp(arg, b) == 0) { - va_end(ap); - return 0; - } - } while (1); - va_end(ap); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, arg); -} - -#ifndef HAVE_MEMPCPY -void *mempcpy(void *restrict dest, const void *restrict src, size_t n) -{ - return ((char *)memcpy(dest, src, n)) + n; -} -#endif - -#ifndef HAVE_STRNLEN -size_t strnlen(const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; i++) { - if (s[i] == '\0') - return i; - } - return maxlen; -} -#endif - -#ifndef HAVE_STRNCHR -char *strnchr(const char *s, size_t maxlen, int c) -{ - for (; maxlen-- && *s != '\0'; ++s) - if (*s == (char)c) - return (char *)s; - return NULL; -} -#endif - -#ifndef HAVE_STRNDUP -char *strndup(const char *s, size_t n) -{ - size_t len = strnlen(s, n); - char *new = malloc((len + 1) * sizeof(char)); - if (!new) - return NULL; - new[len] = '\0'; - return (char *) memcpy(new, s, len); -} -#endif - -static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base); -static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base); - -int16_t strtos16_or_err(const char *str, const char *errmesg) -{ - int32_t num = strtos32_or_err(str, errmesg); - - if (num < INT16_MIN || num > INT16_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; -} - -static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base) -{ - uint32_t num = _strtou32_or_err(str, errmesg, base); - - if (num > UINT16_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; -} - -uint16_t strtou16_or_err(const char *str, const char *errmesg) -{ - return _strtou16_or_err(str, errmesg, 10); -} - -uint16_t strtox16_or_err(const char *str, const char *errmesg) -{ - return _strtou16_or_err(str, errmesg, 16); -} - -int32_t strtos32_or_err(const char *str, const char *errmesg) -{ - int64_t num = strtos64_or_err(str, errmesg); - - if (num < INT32_MIN || num > INT32_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; -} - -static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base) -{ - uint64_t num = _strtou64_or_err(str, errmesg, base); - - if (num > UINT32_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; -} - -uint32_t strtou32_or_err(const char *str, const char *errmesg) -{ - return _strtou32_or_err(str, errmesg, 10); -} - -uint32_t strtox32_or_err(const char *str, const char *errmesg) -{ - return _strtou32_or_err(str, errmesg, 16); -} - -int64_t strtos64_or_err(const char *str, const char *errmesg) -{ - int64_t num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtoimax(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base) -{ - uintmax_t num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtoumax(str, &end, base); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -uint64_t strtou64_or_err(const char *str, const char *errmesg) -{ - return _strtou64_or_err(str, errmesg, 10); -} - -uint64_t strtox64_or_err(const char *str, const char *errmesg) -{ - return _strtou64_or_err(str, errmesg, 16); -} - -double strtod_or_err(const char *str, const char *errmesg) -{ - double num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtod(str, &end); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -long strtol_or_err(const char *str, const char *errmesg) -{ - long num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtol(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -unsigned long strtoul_or_err(const char *str, const char *errmesg) -{ - unsigned long num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtoul(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -uintmax_t strtosize_or_err(const char *str, const char *errmesg) -{ - uintmax_t num; - - if (strtosize(str, &num) == 0) - return num; - - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - - -void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg) -{ - double user_input; - - user_input = strtod_or_err(str, errmesg); - tv->tv_sec = (time_t) user_input; - tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000); -} - -/* - * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must - * be 11 bytes. - */ -char *xstrmode(mode_t mode, char *str) -{ - unsigned short i = 0; - - if (S_ISDIR(mode)) - str[i++] = 'd'; - else if (S_ISLNK(mode)) - str[i++] = 'l'; - else if (S_ISCHR(mode)) - str[i++] = 'c'; - else if (S_ISBLK(mode)) - str[i++] = 'b'; - else if (S_ISSOCK(mode)) - str[i++] = 's'; - else if (S_ISFIFO(mode)) - str[i++] = 'p'; - else if (S_ISREG(mode)) - str[i++] = '-'; - - str[i++] = mode & S_IRUSR ? 'r' : '-'; - str[i++] = mode & S_IWUSR ? 'w' : '-'; - str[i++] = (mode & S_ISUID - ? (mode & S_IXUSR ? 's' : 'S') - : (mode & S_IXUSR ? 'x' : '-')); - str[i++] = mode & S_IRGRP ? 'r' : '-'; - str[i++] = mode & S_IWGRP ? 'w' : '-'; - str[i++] = (mode & S_ISGID - ? (mode & S_IXGRP ? 's' : 'S') - : (mode & S_IXGRP ? 'x' : '-')); - str[i++] = mode & S_IROTH ? 'r' : '-'; - str[i++] = mode & S_IWOTH ? 'w' : '-'; - str[i++] = (mode & S_ISVTX - ? (mode & S_IXOTH ? 't' : 'T') - : (mode & S_IXOTH ? 'x' : '-')); - str[i] = '\0'; - - return str; -} - -/* - * returns exponent (2^x=n) in range KiB..EiB (2^10..2^60) - */ -static int get_exp(uint64_t n) -{ - int shft; - - for (shft = 10; shft <= 60; shft += 10) { - if (n < (1ULL << shft)) - break; - } - return shft - 10; -} - -char *size_to_human_string(int options, uint64_t bytes) -{ - char buf[32]; - int dec, exp; - uint64_t frac; - const char *letters = "BKMGTPE"; - char suffix[sizeof(" KiB")], *psuf = suffix; - char c; - - if (options & SIZE_SUFFIX_SPACE) - *psuf++ = ' '; - - - exp = get_exp(bytes); - c = *(letters + (exp ? exp / 10 : 0)); - dec = exp ? bytes / (1ULL << exp) : bytes; - frac = exp ? bytes % (1ULL << exp) : 0; - - *psuf++ = c; - - if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) { - *psuf++ = 'i'; - *psuf++ = 'B'; - } - - *psuf = '\0'; - - /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n", - * exp, suffix[0], dec, frac); - */ - - /* round */ - if (frac) { - /* get 3 digits after decimal point */ - if (frac >= UINT64_MAX / 1000) - frac = ((frac / 1024) * 1000) / (1ULL << (exp - 10)) ; - else - frac = (frac * 1000) / (1ULL << (exp)) ; - - if (options & SIZE_DECIMAL_2DIGITS) { - /* round 4/5 and keep 2 digits after decimal point */ - frac = (frac + 5) / 10 ; - } else { - /* round 4/5 and keep 1 digit after decimal point */ - frac = ((frac + 50) / 100) * 10 ; - } - - /* rounding could have overflowed */ - if (frac == 100) { - dec++; - frac = 0; - } - } - - if (frac) { - struct lconv const *l = localeconv(); - char *dp = l ? l->decimal_point : NULL; - int len; - - if (!dp || !*dp) - dp = "."; - - len = snprintf(buf, sizeof(buf), "%d%s%02" PRIu64, dec, dp, frac); - if (len > 0 && (size_t) len < sizeof(buf)) { - /* remove potential extraneous zero */ - if (buf[len - 1] == '0') - buf[len--] = '\0'; - /* append suffix */ - xstrncpy(buf+len, suffix, sizeof(buf) - len); - } else - *buf = '\0'; /* snprintf error */ - } else - snprintf(buf, sizeof(buf), "%d%s", dec, suffix); - - return strdup(buf); -} - -/* - * Parses comma delimited list to array with IDs, for example: - * - * "aaa,bbb,ccc" --> ary[0] = FOO_AAA; - * ary[1] = FOO_BBB; - * ary[3] = FOO_CCC; - * - * The function name2id() provides conversion from string to ID. - * - * Returns: >= 0 : number of items added to ary[] - * -1 : parse error or unknown item - * -2 : arysz reached - */ -int string_to_idarray(const char *list, int ary[], size_t arysz, - int (name2id)(const char *, size_t)) -{ - const char *begin = NULL, *p; - size_t n = 0; - - if (!list || !*list || !ary || !arysz || !name2id) - return -1; - - for (p = list; p && *p; p++) { - const char *end = NULL; - int id; - - if (n >= arysz) - return -2; - if (!begin) - begin = p; /* begin of the column name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - id = name2id(begin, end - begin); - if (id == -1) - return -1; - ary[ n++ ] = id; - begin = NULL; - if (end && !*end) - break; - } - return n; -} - -/* - * Parses the array like string_to_idarray but if format is "+aaa,bbb" - * it adds fields to array instead of replacing them. - */ -int string_add_to_idarray(const char *list, int ary[], size_t arysz, - size_t *ary_pos, int (name2id)(const char *, size_t)) -{ - const char *list_add; - int r; - - if (!list || !*list || !ary_pos || *ary_pos > arysz) - return -1; - - if (list[0] == '+') - list_add = &list[1]; - else { - list_add = list; - *ary_pos = 0; - } - - r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id); - if (r > 0) - *ary_pos += r; - return r; -} - -/* - * LIST ::= [, ] - * - * The is translated to 'id' by name2id() function and the 'id' is used - * as a position in the 'ary' bit array. It means that the 'id' has to be in - * range <0..N> where N < sizeof(ary) * NBBY. - * - * Returns: 0 on success, <0 on error. - */ -int string_to_bitarray(const char *list, - char *ary, - int (*name2bit)(const char *, size_t)) -{ - const char *begin = NULL, *p; - - if (!list || !name2bit || !ary) - return -EINVAL; - - for (p = list; p && *p; p++) { - const char *end = NULL; - int bit; - - if (!begin) - begin = p; /* begin of the level name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - bit = name2bit(begin, end - begin); - if (bit < 0) - return bit; - setbit(ary, bit); - begin = NULL; - if (end && !*end) - break; - } - return 0; -} - -/* - * LIST ::= [, ] - * - * The is translated to 'id' by name2flag() function and the flags is - * set to the 'mask' -* - * Returns: 0 on success, <0 on error. - */ -int string_to_bitmask(const char *list, - unsigned long *mask, - long (*name2flag)(const char *, size_t)) -{ - const char *begin = NULL, *p; - - if (!list || !name2flag || !mask) - return -EINVAL; - - for (p = list; p && *p; p++) { - const char *end = NULL; - long flag; - - if (!begin) - begin = p; /* begin of the level name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - flag = name2flag(begin, end - begin); - if (flag < 0) - return flag; /* error */ - *mask |= flag; - begin = NULL; - if (end && !*end) - break; - } - return 0; -} - -/* - * Parse the lower and higher values in a string containing - * "lower:higher" or "lower-higher" format. Note that either - * the lower or the higher values may be missing, and the def - * value will be assigned to it by default. - * - * Returns: 0 on success, <0 on error. - */ -int parse_range(const char *str, int *lower, int *upper, int def) -{ - char *end = NULL; - - if (!str) - return 0; - - *upper = *lower = def; - errno = 0; - - if (*str == ':') { /* <:N> */ - str++; - *upper = strtol(str, &end, 10); - if (errno || !end || *end || end == str) - return -1; - } else { - *upper = *lower = strtol(str, &end, 10); - if (errno || !end || end == str) - return -1; - - if (*end == ':' && !*(end + 1)) /* */ - *upper = def; - else if (*end == '-' || *end == ':') { /* */ - str = end + 1; - end = NULL; - errno = 0; - *upper = strtol(str, &end, 10); - - if (errno || !end || *end || end == str) - return -1; - } - } - return 0; -} - -static const char *next_path_segment(const char *str, size_t *sz) -{ - const char *start, *p; - - start = str; - *sz = 0; - while (start && *start == '/' && *(start + 1) == '/') - start++; - - if (!start || !*start) - return NULL; - - for (*sz = 1, p = start + 1; *p && *p != '/'; p++) { - (*sz)++; - } - - return start; -} - -int streq_paths(const char *a, const char *b) -{ - while (a && b) { - size_t a_sz, b_sz; - const char *a_seg = next_path_segment(a, &a_sz); - const char *b_seg = next_path_segment(b, &b_sz); - - /* - fprintf(stderr, "A>>>(%zu) '%s'\n", a_sz, a_seg); - fprintf(stderr, "B>>>(%zu) '%s'\n", b_sz, b_seg); - */ - - /* end of the path */ - if (a_sz + b_sz == 0) - return 1; - - /* ignore tailing slash */ - if (a_sz + b_sz == 1 && - ((a_seg && *a_seg == '/') || (b_seg && *b_seg == '/'))) - return 1; - - if (!a_seg || !b_seg) - break; - if (a_sz != b_sz || strncmp(a_seg, b_seg, a_sz) != 0) - break; - - a = a_seg + a_sz; - b = b_seg + b_sz; - }; - - return 0; -} - -char *strnappend(const char *s, const char *suffix, size_t b) -{ - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - if (!s) - return strndup(suffix, b); - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = malloc(a + b + 1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r + a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) -{ - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -char *strfappend(const char *s, const char *format, ...) -{ - va_list ap; - char *val, *res; - int sz; - - va_start(ap, format); - sz = vasprintf(&val, format, ap); - va_end(ap); - - if (sz < 0) - return NULL; - - res = strnappend(s, val, sz); - free(val); - return res; -} - -static size_t strcspn_escaped(const char *s, const char *reject) -{ - int escaped = 0; - int n; - - for (n=0; s[n]; n++) { - if (escaped) - escaped = 0; - else if (s[n] == '\\') - escaped = 1; - else if (strchr(reject, s[n])) - break; - } - - /* if s ends in \, return index of previous char */ - return n - escaped; -} - -/* Split a string into words. */ -const char *split(const char **state, size_t *l, const char *separator, int quoted) -{ - const char *current; - - current = *state; - - if (!*current) { - assert(**state == '\0'); - return NULL; - } - - current += strspn(current, separator); - if (!*current) { - *state = current; - return NULL; - } - - if (quoted && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; - - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end */ - *state = current; - return NULL; - } - *state = current++ + *l + 2; - } else if (quoted) { - *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l])) { - /* unfinished escape */ - *state = current; - return NULL; - } - *state = current + *l; - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - -/* Rewind file pointer forward to new line. */ -int skip_fline(FILE *fp) -{ - int ch; - - do { - if ((ch = fgetc(fp)) == EOF) - return 1; - if (ch == '\n') - return 0; - } while (1); -} - -#ifdef TEST_PROGRAM_STRUTILS -struct testS { - char *name; - char *value; -}; - -static int test_strdup_to_member(int argc, char *argv[]) -{ - struct testS *xx; - - if (argc < 3) - return EXIT_FAILURE; - - xx = calloc(1, sizeof(*xx)); - if (!xx) - err(EXIT_FAILURE, "calloc() failed"); - - strdup_to_struct_member(xx, name, argv[1]); - strdup_to_struct_member(xx, value, argv[2]); - - if (strcmp(xx->name, argv[1]) != 0 && - strcmp(xx->value, argv[2]) != 0) - errx(EXIT_FAILURE, "strdup_to_struct_member() failed"); - - printf("1: '%s', 2: '%s'\n", xx->name, xx->value); - - free(xx->name); - free(xx->value); - free(xx); - return EXIT_SUCCESS; -} - -static int test_strutils_sizes(int argc, char *argv[]) -{ - uintmax_t size = 0; - char *hum1, *hum2, *hum3; - - if (argc < 2) - return EXIT_FAILURE; - - if (strtosize(argv[1], &size)) - errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]); - - hum1 = size_to_human_string(SIZE_SUFFIX_1LETTER, size); - hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER | - SIZE_SUFFIX_SPACE, size); - hum3 = size_to_human_string(SIZE_SUFFIX_3LETTER | - SIZE_SUFFIX_SPACE | - SIZE_DECIMAL_2DIGITS, size); - - printf("%25s : %20ju : %8s : %12s : %13s\n", argv[1], size, hum1, hum2, hum3); - free(hum1); - free(hum2); - free(hum3); - - return EXIT_SUCCESS; -} - -static int test_strutils_cmp_paths(int argc, char *argv[]) -{ - int rc = streq_paths(argv[1], argv[2]); - - if (argc < 3) - return EXIT_FAILURE; - - printf("%s: '%s' '%s'\n", rc == 1 ? "YES" : "NOT", argv[1], argv[2]); - return EXIT_SUCCESS; -} - -int main(int argc, char *argv[]) -{ - if (argc == 3 && strcmp(argv[1], "--size") == 0) - return test_strutils_sizes(argc - 1, argv + 1); - - if (argc == 4 && strcmp(argv[1], "--cmp-paths") == 0) - return test_strutils_cmp_paths(argc - 1, argv + 1); - - if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0) - return test_strdup_to_member(argc - 1, argv + 1); - - fprintf(stderr, "usage: %1$s --size [suffix]\n" - " %1$s --cmp-paths \n" - " %1$s --strdup-member \n", - argv[0]); - - return EXIT_FAILURE; -} -#endif /* TEST_PROGRAM_STRUTILS */ diff --git a/utils/lib/strv.c b/utils/lib/strv.c deleted file mode 100644 index ddc2a0c..0000000 --- a/utils/lib/strv.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * - * Copyright 2010 Lennart Poettering - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * - * Copyright (C) 2015 Karel Zak - * Modified the original version from systemd project for util-linux. - */ - -#include -#include -#include -#include -#include -#include - -#include "strutils.h" -#include "strv.h" - -void strv_clear(char **l) { - char **k; - - if (!l) - return; - - for (k = l; *k; k++) - free(*k); - - *l = NULL; -} - -char **strv_free(char **l) { - strv_clear(l); - free(l); - return NULL; -} - -char **strv_copy(char * const *l) { - char **r, **k; - - k = r = malloc(sizeof(char *) * (strv_length(l) + 1)); - if (!r) - return NULL; - - if (l) - for (; *l; k++, l++) { - *k = strdup(*l); - if (!*k) { - strv_free(r); - return NULL; - } - } - - *k = NULL; - return r; -} - -unsigned strv_length(char * const *l) { - unsigned n = 0; - - if (!l) - return 0; - - for (; *l; l++) - n++; - - return n; -} - -char **strv_new_ap(const char *x, va_list ap) { - const char *s; - char **a; - unsigned n = 0, i = 0; - va_list aq; - - /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the - * STRV_IFNOTNULL() macro to include possibly NULL strings in - * the string list. */ - - if (x) { - n = x == (const char*) -1 ? 0 : 1; - - va_copy(aq, ap); - while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) - continue; - - n++; - } - - va_end(aq); - } - - a = malloc(sizeof(char *) * (n + 1)); - if (!a) - return NULL; - - if (x) { - if (x != (const char*) -1) { - a[i] = strdup(x); - if (!a[i]) - goto fail; - i++; - } - - while ((s = va_arg(ap, const char*))) { - - if (s == (const char*) -1) - continue; - - a[i] = strdup(s); - if (!a[i]) - goto fail; - - i++; - } - } - - a[i] = NULL; - - return a; - -fail: - strv_free(a); - return NULL; -} - -char **strv_new(const char *x, ...) { - char **r; - va_list ap; - - va_start(ap, x); - r = strv_new_ap(x, ap); - va_end(ap); - - return r; -} - -int strv_extend_strv(char ***a, char **b) { - int r; - char **s; - - STRV_FOREACH(s, b) { - r = strv_extend(a, *s); - if (r < 0) - return r; - } - - return 0; -} - -int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { - int r; - char **s; - - STRV_FOREACH(s, b) { - char *v; - - v = strappend(*s, suffix); - if (!v) - return -ENOMEM; - - r = strv_push(a, v); - if (r < 0) { - free(v); - return r; - } - } - - return 0; -} - - -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, false, state) - - -char **strv_split(const char *s, const char *separator) { - const char *word, *state; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_SEPARATOR(word, l, s, separator, state) - n++; - - r = malloc(sizeof(char *) * (n + 1)); - if (!r) - return NULL; - - i = 0; - FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { - r[i] = strndup(word, l); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - } - - r[i] = NULL; - return r; -} - -char *strv_join(char **l, const char *separator) { - char *r, *e; - char **s; - size_t n, k; - - if (!separator) - separator = " "; - - k = strlen(separator); - - n = 0; - STRV_FOREACH(s, l) { - if (n != 0) - n += k; - n += strlen(*s); - } - - r = malloc(n + 1); - if (!r) - return NULL; - - e = r; - STRV_FOREACH(s, l) { - if (e != r) - e = stpcpy(e, separator); - - e = stpcpy(e, *s); - } - - *e = 0; - - return r; -} - -int strv_push(char ***l, char *value) { - char **c; - unsigned n, m; - - if (!value) - return 0; - - n = strv_length(*l); - - /* Increase and check for overflow */ - m = n + 2; - if (m < n) - return -ENOMEM; - - c = realloc(*l, sizeof(char *) * m); - if (!c) - return -ENOMEM; - - c[n] = value; - c[n+1] = NULL; - - *l = c; - return 0; -} - -int strv_push_prepend(char ***l, char *value) { - char **c; - unsigned n, m, i; - - if (!value) - return 0; - - n = strv_length(*l); - - /* increase and check for overflow */ - m = n + 2; - if (m < n) - return -ENOMEM; - - c = malloc(sizeof(char *) * m); - if (!c) - return -ENOMEM; - - for (i = 0; i < n; i++) - c[i+1] = (*l)[i]; - - c[0] = value; - c[n+1] = NULL; - - free(*l); - *l = c; - - return 0; -} - -int strv_consume(char ***l, char *value) { - int r; - - r = strv_push(l, value); - if (r < 0) - free(value); - - return r; -} - -int strv_consume_prepend(char ***l, char *value) { - int r; - - r = strv_push_prepend(l, value); - if (r < 0) - free(value); - - return r; -} - -int strv_extend(char ***l, const char *value) { - char *v; - - if (!value) - return 0; - - v = strdup(value); - if (!v) - return -ENOMEM; - - return strv_consume(l, v); -} - -char **strv_remove(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of s in the string list, edits - * in-place. */ - - for (f = t = l; *f; f++) - if (strcmp(*f, s) == 0) - free(*f); - else - *(t++) = *f; - - *t = NULL; - return l; -} - -int strv_extendf(char ***l, const char *format, ...) { - va_list ap; - char *x; - int r; - - va_start(ap, format); - r = vasprintf(&x, format, ap); - va_end(ap); - - if (r < 0) - return -ENOMEM; - - return strv_consume(l, x); -} - -int strv_extendv(char ***l, const char *format, va_list ap) { - char *x; - int r; - - r = vasprintf(&x, format, ap); - if (r < 0) - return -ENOMEM; - - return strv_consume(l, x); -} - -char **strv_reverse(char **l) { - unsigned n, i; - - n = strv_length(l); - if (n <= 1) - return l; - - for (i = 0; i < n / 2; i++) { - char *t; - - t = l[i]; - l[i] = l[n-1-i]; - l[n-1-i] = t; - } - - return l; -} diff --git a/utils/lib/sysfs.c b/utils/lib/sysfs.c deleted file mode 100644 index 5b4de2c..0000000 --- a/utils/lib/sysfs.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak - */ -#include -#include -#include -#include -#include - -#include "c.h" -#include "pathnames.h" -#include "sysfs.h" -#include "fileutils.h" -#include "all-io.h" -#include "debug.h" -#include "strutils.h" - -static void sysfs_blkdev_deinit_path(struct path_cxt *pc); -static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd); - -/* - * Debug stuff (based on include/debug.h) - */ -static UL_DEBUG_DEFINE_MASK(ulsysfs); -UL_DEBUG_DEFINE_MASKNAMES(ulsysfs) = UL_DEBUG_EMPTY_MASKNAMES; - -#define ULSYSFS_DEBUG_INIT (1 << 1) -#define ULSYSFS_DEBUG_CXT (1 << 2) - -#define DBG(m, x) __UL_DBG(ulsysfs, ULSYSFS_DEBUG_, m, x) -#define ON_DBG(m, x) __UL_DBG_CALL(ulsysfs, ULSYSFS_DEBUG_, m, x) - -#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulsysfs) -#include "debugobj.h" - -void ul_sysfs_init_debug(void) -{ - if (ulsysfs_debug_mask) - return; - __UL_INIT_DEBUG_FROM_ENV(ulsysfs, ULSYSFS_DEBUG_, 0, ULSYSFS_DEBUG); -} - -struct path_cxt *ul_new_sysfs_path(dev_t devno, struct path_cxt *parent, const char *prefix) -{ - struct path_cxt *pc = ul_new_path(NULL); - - if (!pc) - return NULL; - if (prefix) - ul_path_set_prefix(pc, prefix); - - if (sysfs_blkdev_init_path(pc, devno, parent) != 0) { - ul_unref_path(pc); - return NULL; - } - - DBG(CXT, ul_debugobj(pc, "alloc")); - return pc; -} - -/* - * sysfs_blkdev_* is sysfs extension to ul_path_* API for block devices. - * - * The function is possible to call in loop and without sysfs_blkdev_deinit_path(). - * The sysfs_blkdev_deinit_path() is automatically called by ul_unref_path(). - * - */ -int sysfs_blkdev_init_path(struct path_cxt *pc, dev_t devno, struct path_cxt *parent) -{ - struct sysfs_blkdev *blk; - int rc; - char buf[sizeof(_PATH_SYS_DEVBLOCK) - + sizeof(stringify_value(UINT32_MAX)) * 2 - + 3]; - - /* define path to devno stuff */ - snprintf(buf, sizeof(buf), _PATH_SYS_DEVBLOCK "/%d:%d", major(devno), minor(devno)); - rc = ul_path_set_dir(pc, buf); - if (rc) - return rc; - - /* make sure path exists */ - rc = ul_path_get_dirfd(pc); - if (rc < 0) - return rc; - - /* initialize sysfs blkdev specific stuff */ - blk = ul_path_get_dialect(pc); - if (!blk) { - DBG(CXT, ul_debugobj(pc, "alloc new sysfs handler")); - blk = calloc(1, sizeof(struct sysfs_blkdev)); - if (!blk) - return -ENOMEM; - - ul_path_set_dialect(pc, blk, sysfs_blkdev_deinit_path); - ul_path_set_enoent_redirect(pc, sysfs_blkdev_enoent_redirect); - } - - DBG(CXT, ul_debugobj(pc, "init sysfs stuff")); - - blk->devno = devno; - sysfs_blkdev_set_parent(pc, parent); - - return 0; -} - -static void sysfs_blkdev_deinit_path(struct path_cxt *pc) -{ - struct sysfs_blkdev *blk; - - if (!pc) - return; - - DBG(CXT, ul_debugobj(pc, "deinit")); - - blk = ul_path_get_dialect(pc); - if (!blk) - return; - - ul_unref_path(blk->parent); - free(blk); - - ul_path_set_dialect(pc, NULL, NULL); -} - -int sysfs_blkdev_set_parent(struct path_cxt *pc, struct path_cxt *parent) -{ - struct sysfs_blkdev *blk = ul_path_get_dialect(pc); - - if (!pc || !blk) - return -EINVAL; - - if (blk->parent) { - ul_unref_path(blk->parent); - blk->parent = NULL; - } - - if (parent) { - ul_ref_path(parent); - blk->parent = parent; - } else - blk->parent = NULL; - - DBG(CXT, ul_debugobj(pc, "new parent")); - return 0; -} - -struct path_cxt *sysfs_blkdev_get_parent(struct path_cxt *pc) -{ - struct sysfs_blkdev *blk = ul_path_get_dialect(pc); - return blk ? blk->parent : NULL; -} - -/* - * Redirects ENOENT errors to the parent, if the path is to the queue/ - * sysfs directory. For example - * - * /sys/dev/block/8:1/queue/logical_block_size redirects to - * /sys/dev/block/8:0/queue/logical_block_size - */ -static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd) -{ - struct sysfs_blkdev *blk = ul_path_get_dialect(pc); - - if (blk && blk->parent && strncmp(path, "queue/", 6) == 0) { - *dirfd = ul_path_get_dirfd(blk->parent); - if (*dirfd >= 0) { - DBG(CXT, ul_debugobj(pc, "%s redirected to parent", path)); - return 0; - } - } - return 1; /* no redirect */ -} - -char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz) -{ - char link[PATH_MAX]; - char *name; - ssize_t sz; - - /* read /sys/dev/block/ link */ - sz = ul_path_readlink(pc, link, sizeof(link) - 1, NULL); - if (sz < 0) - return NULL; - link[sz] = '\0'; - - name = strrchr(link, '/'); - if (!name) - return NULL; - - name++; - sz = strlen(name); - if ((size_t) sz + 1 > bufsiz) - return NULL; - - memcpy(buf, name, sz + 1); - sysfs_devname_sys_to_dev(buf); - return buf; -} - -int sysfs_blkdev_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name) -{ - char path[NAME_MAX + 6 + 1]; - -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_DIR && - d->d_type != DT_LNK && - d->d_type != DT_UNKNOWN) - return 0; -#endif - if (parent_name) { - const char *p = parent_name; - size_t len; - - /* /dev/sda --> "sda" */ - if (*parent_name == '/') { - p = strrchr(parent_name, '/'); - if (!p) - return 0; - p++; - } - - len = strlen(p); - if (strlen(d->d_name) <= len) - return 0; - - /* partitions subdir name is - * "[:digit:]" or "p[:digit:]" - */ - return strncmp(p, d->d_name, len) == 0 && - ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1))) - || isdigit(*(d->d_name + len))); - } - - /* Cannot use /partition file, not supported on old sysfs */ - snprintf(path, sizeof(path), "%s/start", d->d_name); - - return faccessat(dirfd(dir), path, R_OK, 0) == 0; -} - -int sysfs_blkdev_count_partitions(struct path_cxt *pc, const char *devname) -{ - DIR *dir; - struct dirent *d; - int r = 0; - - dir = ul_path_opendir(pc, NULL); - if (!dir) - return 0; - - while ((d = xreaddir(dir))) { - if (sysfs_blkdev_is_partition_dirent(dir, d, devname)) - r++; - } - - closedir(dir); - return r; -} - -/* - * Converts @partno (partition number) to devno of the partition. - * The @pc handles wholedisk device. - * - * Note that this code does not expect any special format of the - * partitions devnames. - */ -dev_t sysfs_blkdev_partno_to_devno(struct path_cxt *pc, int partno) -{ - DIR *dir; - struct dirent *d; - dev_t devno = 0; - - dir = ul_path_opendir(pc, NULL); - if (!dir) - return 0; - - while ((d = xreaddir(dir))) { - int n; - - if (!sysfs_blkdev_is_partition_dirent(dir, d, NULL)) - continue; - - if (ul_path_readf_s32(pc, &n, "%s/partition", d->d_name)) - continue; - - if (n == partno) { - if (ul_path_readf_majmin(pc, &devno, "%s/dev", d->d_name) == 0) - break; - } - } - - closedir(dir); - DBG(CXT, ul_debugobj(pc, "partno (%d) -> devno (%d)", (int) partno, (int) devno)); - return devno; -} - - -/* - * Returns slave name if there is only one slave, otherwise returns NULL. - * The result should be deallocated by free(). - */ -char *sysfs_blkdev_get_slave(struct path_cxt *pc) -{ - DIR *dir; - struct dirent *d; - char *name = NULL; - - dir = ul_path_opendir(pc, "slaves"); - if (!dir) - return NULL; - - while ((d = xreaddir(dir))) { - if (name) - goto err; /* more slaves */ - name = strdup(d->d_name); - } - - closedir(dir); - return name; -err: - free(name); - closedir(dir); - return NULL; -} - - -#define SUBSYSTEM_LINKNAME "/subsystem" - -/* - * For example: - * - * chain: /sys/dev/block/../../devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/ \ - * 1-1.2:1.0/host65/target65:0:0/65:0:0:0/block/sdb - * - * The function check if /subsystem symlink exists, if yes then returns - * basename of the readlink result, and remove the last subdirectory from the - * path. - */ -static char *get_subsystem(char *chain, char *buf, size_t bufsz) -{ - size_t len; - char *p; - - if (!chain || !*chain) - return NULL; - - len = strlen(chain); - if (len + sizeof(SUBSYSTEM_LINKNAME) > PATH_MAX) - return NULL; - - do { - ssize_t sz; - - /* append "/subsystem" to the path */ - memcpy(chain + len, SUBSYSTEM_LINKNAME, sizeof(SUBSYSTEM_LINKNAME)); - - /* try if subsystem symlink exists */ - sz = readlink(chain, buf, bufsz - 1); - - /* remove last subsystem from chain */ - chain[len] = '\0'; - p = strrchr(chain, '/'); - if (p) { - *p = '\0'; - len = p - chain; - } - - if (sz > 0) { - /* we found symlink to subsystem, return basename */ - buf[sz] = '\0'; - return basename(buf); - } - - } while (p); - - return NULL; -} - -/* - * Returns complete path to the device, the patch contains all subsystems - * used for the device. - */ -char *sysfs_blkdev_get_devchain(struct path_cxt *pc, char *buf, size_t bufsz) -{ - /* read /sys/dev/block/: symlink */ - ssize_t sz = ul_path_readlink(pc, buf, bufsz, NULL); - const char *prefix; - size_t psz = 0; - - if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz) - return NULL; - - buf[sz++] = '\0'; - prefix = ul_path_get_prefix(pc); - if (prefix) - psz = strlen(prefix); - - /* create absolute patch from the link */ - memmove(buf + psz + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz); - if (prefix) - memcpy(buf, prefix, psz); - - memcpy(buf + psz, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1); - return buf; -} - -/* - * The @subsys returns the next subsystem in the chain. Function modifies - * @devchain string. - * - * Returns: 0 in success, <0 on error, 1 on end of chain - */ -int sysfs_blkdev_next_subsystem(struct path_cxt *pc __attribute__((unused)), - char *devchain, char **subsys) -{ - char subbuf[PATH_MAX]; - char *sub; - - if (!subsys || !devchain) - return -EINVAL; - - *subsys = NULL; - - while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) { - *subsys = strdup(sub); - if (!*subsys) - return -ENOMEM; - return 0; - } - - return 1; -} - - -static int is_hotpluggable_subsystem(const char *name) -{ - static const char * const hotplug_subsystems[] = { - "usb", - "ieee1394", - "pcmcia", - "mmc", - "ccw" - }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(hotplug_subsystems); i++) - if (strcmp(name, hotplug_subsystems[i]) == 0) - return 1; - - return 0; -} - -int sysfs_blkdev_is_hotpluggable(struct path_cxt *pc) -{ - char buf[PATH_MAX], *chain, *sub; - int rc = 0; - - - /* check /sys/dev/block/:/removable attribute */ - if (ul_path_read_s32(pc, &rc, "removable") == 0 && rc == 1) - return 1; - - chain = sysfs_blkdev_get_devchain(pc, buf, sizeof(buf)); - - while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) { - rc = is_hotpluggable_subsystem(sub); - if (rc) { - free(sub); - break; - } - free(sub); - } - - return rc; -} - -static int get_dm_wholedisk(struct path_cxt *pc, char *diskname, - size_t len, dev_t *diskdevno) -{ - int rc = 0; - char *name; - - /* Note, sysfs_blkdev_get_slave() returns the first slave only, - * if there is more slaves, then return NULL - */ - name = sysfs_blkdev_get_slave(pc); - if (!name) - return -1; - - if (diskname && len) - xstrncpy(diskname, name, len); - - if (diskdevno) { - *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL); - if (!*diskdevno) - rc = -1; - } - - free(name); - return rc; -} - -/* - * Returns by @diskdevno whole disk device devno and (optionally) by - * @diskname the whole disk device name. - */ -int sysfs_blkdev_get_wholedisk( struct path_cxt *pc, - char *diskname, - size_t len, - dev_t *diskdevno) -{ - int is_part = 0; - - if (!pc) - return -1; - - is_part = ul_path_access(pc, F_OK, "partition") == 0; - if (!is_part) { - /* - * Extra case for partitions mapped by device-mapper. - * - * All regular partitions (added by BLKPG ioctl or kernel PT - * parser) have the /sys/.../partition file. The partitions - * mapped by DM don't have such file, but they have "part" - * prefix in DM UUID. - */ - char *uuid = NULL, *tmp, *prefix; - - ul_path_read_string(pc, &uuid, "dm/uuid"); - tmp = uuid; - prefix = uuid ? strsep(&tmp, "-") : NULL; - - if (prefix && strncasecmp(prefix, "part", 4) == 0) - is_part = 1; - free(uuid); - - if (is_part && - get_dm_wholedisk(pc, diskname, len, diskdevno) == 0) - /* - * partitioned device, mapped by DM - */ - goto done; - - is_part = 0; - } - - if (!is_part) { - /* - * unpartitioned device - */ - if (diskname && !sysfs_blkdev_get_name(pc, diskname, len)) - goto err; - if (diskdevno) - *diskdevno = sysfs_blkdev_get_devno(pc); - - } else { - /* - * partitioned device - * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1 - * - dirname ../../block/sda/sda1 = ../../block/sda - * - basename ../../block/sda = sda - */ - char linkpath[PATH_MAX]; - char *name; - ssize_t linklen; - - linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath) - 1, NULL); - if (linklen < 0) - goto err; - linkpath[linklen] = '\0'; - - stripoff_last_component(linkpath); /* dirname */ - name = stripoff_last_component(linkpath); /* basename */ - if (!name) - goto err; - - sysfs_devname_sys_to_dev(name); - if (diskname && len) - xstrncpy(diskname, name, len); - - if (diskdevno) { - *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL); - if (!*diskdevno) - goto err; - } - } - -done: - return 0; -err: - return -1; -} - -int sysfs_devno_to_wholedisk(dev_t devno, char *diskname, - size_t len, dev_t *diskdevno) -{ - struct path_cxt *pc; - int rc = 0; - - if (!devno) - return -EINVAL; - pc = ul_new_sysfs_path(devno, NULL, NULL); - if (!pc) - return -ENOMEM; - - rc = sysfs_blkdev_get_wholedisk(pc, diskname, len, diskdevno); - ul_unref_path(pc); - return rc; -} - -/* - * Returns 1 if the device is private device mapper device. The @uuid - * (if not NULL) returns DM device UUID, use free() to deallocate. - */ -int sysfs_devno_is_dm_private(dev_t devno, char **uuid) -{ - struct path_cxt *pc = NULL; - char *id = NULL; - int rc = 0; - - pc = ul_new_sysfs_path(devno, NULL, NULL); - if (!pc) - goto done; - if (ul_path_read_string(pc, &id, "dm/uuid") <= 0 || !id) - goto done; - - /* Private LVM devices use "LVM--" uuid format (important - * is the "LVM" prefix and "-" postfix). - */ - if (strncmp(id, "LVM-", 4) == 0) { - char *p = strrchr(id + 4, '-'); - - if (p && *(p + 1)) - rc = 1; - - /* Private Stratis devices prefix the UUID with "stratis-1-private" - */ - } else if (strncmp(id, "stratis-1-private", 17) == 0) { - rc = 1; - } -done: - ul_unref_path(pc); - if (uuid) - *uuid = id; - else - free(id); - return rc; -} - -/* - * Return 0 or 1, or < 0 in case of error - */ -int sysfs_devno_is_wholedisk(dev_t devno) -{ - dev_t disk; - - if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0) - return -1; - - return devno == disk; -} - - -int sysfs_blkdev_scsi_get_hctl(struct path_cxt *pc, int *h, int *c, int *t, int *l) -{ - char buf[PATH_MAX], *hctl; - struct sysfs_blkdev *blk; - ssize_t len; - - blk = ul_path_get_dialect(pc); - - if (!blk || blk->hctl_error) - return -EINVAL; - if (blk->has_hctl) - goto done; - - blk->hctl_error = 1; - len = ul_path_readlink(pc, buf, sizeof(buf) - 1, "device"); - if (len < 0) - return len; - - buf[len] = '\0'; - hctl = strrchr(buf, '/'); - if (!hctl) - return -1; - hctl++; - - if (sscanf(hctl, "%u:%u:%u:%u", &blk->scsi_host, &blk->scsi_channel, - &blk->scsi_target, &blk->scsi_lun) != 4) - return -1; - - blk->has_hctl = 1; -done: - if (h) - *h = blk->scsi_host; - if (c) - *c = blk->scsi_channel; - if (t) - *t = blk->scsi_target; - if (l) - *l = blk->scsi_lun; - - blk->hctl_error = 0; - return 0; -} - - -static char *scsi_host_attribute_path( - struct path_cxt *pc, - const char *type, - char *buf, - size_t bufsz, - const char *attr) -{ - int len; - int host; - const char *prefix; - - if (sysfs_blkdev_scsi_get_hctl(pc, &host, NULL, NULL, NULL)) - return NULL; - - prefix = ul_path_get_prefix(pc); - if (!prefix) - prefix = ""; - - if (attr) - len = snprintf(buf, bufsz, "%s%s/%s_host/host%d/%s", - prefix, _PATH_SYS_CLASS, type, host, attr); - else - len = snprintf(buf, bufsz, "%s%s/%s_host/host%d", - prefix, _PATH_SYS_CLASS, type, host); - - return (len < 0 || (size_t) len >= bufsz) ? NULL : buf; -} - -char *sysfs_blkdev_scsi_host_strdup_attribute(struct path_cxt *pc, - const char *type, const char *attr) -{ - char buf[1024]; - int rc; - FILE *f; - - if (!attr || !type || - !scsi_host_attribute_path(pc, type, buf, sizeof(buf), attr)) - return NULL; - - if (!(f = fopen(buf, "r" UL_CLOEXECSTR))) - return NULL; - - rc = fscanf(f, "%1023[^\n]", buf); - fclose(f); - - return rc == 1 ? strdup(buf) : NULL; -} - -int sysfs_blkdev_scsi_host_is(struct path_cxt *pc, const char *type) -{ - char buf[PATH_MAX]; - struct stat st; - - if (!type || !scsi_host_attribute_path(pc, type, - buf, sizeof(buf), NULL)) - return 0; - - return stat(buf, &st) == 0 && S_ISDIR(st.st_mode); -} - -static char *scsi_attribute_path(struct path_cxt *pc, - char *buf, size_t bufsz, const char *attr) -{ - int len, h, c, t, l; - const char *prefix; - - if (sysfs_blkdev_scsi_get_hctl(pc, &h, &c, &t, &l) != 0) - return NULL; - - prefix = ul_path_get_prefix(pc); - if (!prefix) - prefix = ""; - - if (attr) - len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d/%s", - prefix, _PATH_SYS_SCSI, - h,c,t,l, attr); - else - len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d", - prefix, _PATH_SYS_SCSI, - h,c,t,l); - return (len < 0 || (size_t) len >= bufsz) ? NULL : buf; -} - -int sysfs_blkdev_scsi_has_attribute(struct path_cxt *pc, const char *attr) -{ - char path[PATH_MAX]; - struct stat st; - - if (!scsi_attribute_path(pc, path, sizeof(path), attr)) - return 0; - - return stat(path, &st) == 0; -} - -int sysfs_blkdev_scsi_path_contains(struct path_cxt *pc, const char *pattern) -{ - char path[PATH_MAX], linkc[PATH_MAX]; - struct stat st; - ssize_t len; - - if (!scsi_attribute_path(pc, path, sizeof(path), NULL)) - return 0; - - if (stat(path, &st) != 0) - return 0; - - len = readlink(path, linkc, sizeof(linkc) - 1); - if (len < 0) - return 0; - - linkc[len] = '\0'; - return strstr(linkc, pattern) != NULL; -} - -static dev_t read_devno(const char *path) -{ - FILE *f; - int maj = 0, min = 0; - dev_t dev = 0; - - f = fopen(path, "r" UL_CLOEXECSTR); - if (!f) - return 0; - - if (fscanf(f, "%d:%d", &maj, &min) == 2) - dev = makedev(maj, min); - fclose(f); - return dev; -} - -int sysfs_devname_is_hidden(const char *prefix, const char *name) -{ - char buf[PATH_MAX]; - int rc = 0, hidden = 0, len; - FILE *f; - - if (strncmp("/dev/", name, 5) == 0) - return 0; - - if (!prefix) - prefix = ""; - /* - * Create path to /sys/block//hidden - */ - len = snprintf(buf, sizeof(buf), - "%s" _PATH_SYS_BLOCK "/%s/hidden", - prefix, name); - - if (len < 0 || (size_t) len + 1 > sizeof(buf)) - return 0; - - f = fopen(buf, "r" UL_CLOEXECSTR); - if (!f) - return 0; - - rc = fscanf(f, "%d", &hidden); - fclose(f); - - return rc == 1 ? hidden : 0; -} - - -dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent) -{ - char buf[PATH_MAX]; - char *_name = NULL; /* name as encoded in sysfs */ - dev_t dev = 0; - int len; - - if (!prefix) - prefix = ""; - - assert(name); - - if (strncmp("/dev/", name, 5) == 0) { - /* - * Read from /dev - */ - struct stat st; - - if (stat(name, &st) == 0) { - dev = st.st_rdev; - goto done; - } - name += 5; /* unaccessible, or not node in /dev */ - } - - _name = strdup(name); - if (!_name) - goto done; - sysfs_devname_dev_to_sys(_name); - - if (parent && strncmp("dm-", name, 3) != 0) { - /* - * Create path to /sys/block///dev - */ - char *_parent = strdup(parent); - - if (!_parent) { - free(_parent); - goto done; - } - sysfs_devname_dev_to_sys(_parent); - len = snprintf(buf, sizeof(buf), - "%s" _PATH_SYS_BLOCK "/%s/%s/dev", - prefix, _parent, _name); - free(_parent); - if (len < 0 || (size_t) len >= sizeof(buf)) - goto done; - - /* don't try anything else for dm-* */ - dev = read_devno(buf); - goto done; - } - - /* - * Read from /sys/block//dev - */ - len = snprintf(buf, sizeof(buf), - "%s" _PATH_SYS_BLOCK "/%s/dev", - prefix, _name); - if (len < 0 || (size_t) len >= sizeof(buf)) - goto done; - dev = read_devno(buf); - - if (!dev) { - /* - * Read from /sys/block//device/dev - */ - len = snprintf(buf, sizeof(buf), - "%s" _PATH_SYS_BLOCK "/%s/device/dev", - prefix, _name); - if (len < 0 || (size_t) len >= sizeof(buf)) - goto done; - dev = read_devno(buf); - } -done: - free(_name); - return dev; -} - -dev_t sysfs_devname_to_devno(const char *name) -{ - return __sysfs_devname_to_devno(NULL, name, NULL); -} - -char *sysfs_blkdev_get_path(struct path_cxt *pc, char *buf, size_t bufsiz) -{ - const char *name = sysfs_blkdev_get_name(pc, buf, bufsiz); - char *res = NULL; - size_t sz; - struct stat st; - - if (!name) - goto done; - - sz = strlen(name); - if (sz + sizeof("/dev/") > bufsiz) - goto done; - - /* create the final "/dev/" string */ - memmove(buf + 5, name, sz + 1); - memcpy(buf, "/dev/", 5); - - if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == sysfs_blkdev_get_devno(pc)) - res = buf; -done: - return res; -} - -dev_t sysfs_blkdev_get_devno(struct path_cxt *pc) -{ - return ((struct sysfs_blkdev *) ul_path_get_dialect(pc))->devno; -} - -/* - * Returns devname (e.g. "/dev/sda1") for the given devno. - * - * Please, use more robust blkid_devno_to_devname() in your applications. - */ -char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz) -{ - struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL); - char *res = NULL; - - if (pc) { - res = sysfs_blkdev_get_path(pc, buf, bufsiz); - ul_unref_path(pc); - } - return res; -} - -char *sysfs_devno_to_devname(dev_t devno, char *buf, size_t bufsiz) -{ - struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL); - char *res = NULL; - - if (pc) { - res = sysfs_blkdev_get_name(pc, buf, bufsiz); - ul_unref_path(pc); - } - return res; -} - -int sysfs_devno_count_partitions(dev_t devno) -{ - struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL); - int n = 0; - - if (pc) { - char buf[PATH_MAX + 1]; - char *name = sysfs_blkdev_get_name(pc, buf, sizeof(buf)); - - n = sysfs_blkdev_count_partitions(pc, name); - ul_unref_path(pc); - } - return n; -} - - -#ifdef TEST_PROGRAM_SYSFS -#include -#include -#include - -int main(int argc, char *argv[]) -{ - struct path_cxt *pc; - char *devname; - dev_t devno, disk_devno; - char path[PATH_MAX], *sub, *chain; - char diskname[32]; - int i, is_part, rc = EXIT_SUCCESS; - uint64_t u64; - - if (argc != 2) - errx(EXIT_FAILURE, "usage: %s ", argv[0]); - - ul_sysfs_init_debug(); - - devname = argv[1]; - devno = sysfs_devname_to_devno(devname); - - if (!devno) - err(EXIT_FAILURE, "failed to read devno"); - - printf("non-context:\n"); - printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno)); - printf(" DEVNAME: %s\n", sysfs_devno_to_devname(devno, path, sizeof(path))); - printf(" DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path))); - - sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno); - printf(" WHOLEDISK-DEVNO: %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno)); - printf(" WHOLEDISK-DEVNAME: %s\n", diskname); - - pc = ul_new_sysfs_path(devno, NULL, NULL); - if (!pc) - goto done; - - printf("context based:\n"); - devno = sysfs_blkdev_get_devno(pc); - printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno)); - printf(" DEVNAME: %s\n", sysfs_blkdev_get_name(pc, path, sizeof(path))); - printf(" DEVPATH: %s\n", sysfs_blkdev_get_path(pc, path, sizeof(path))); - - sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno); - printf(" WHOLEDISK-DEVNO: %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno)); - printf(" WHOLEDISK-DEVNAME: %s\n", diskname); - - is_part = ul_path_access(pc, F_OK, "partition") == 0; - printf(" PARTITION: %s\n", is_part ? "YES" : "NOT"); - - if (is_part && disk_devno) { - struct path_cxt *disk_pc = ul_new_sysfs_path(disk_devno, NULL, NULL); - sysfs_blkdev_set_parent(pc, disk_pc); - - ul_unref_path(disk_pc); - } - - printf(" HOTPLUG: %s\n", sysfs_blkdev_is_hotpluggable(pc) ? "yes" : "no"); - printf(" SLAVES: %d\n", ul_path_count_dirents(pc, "slaves")); - - if (!is_part) { - printf("First 5 partitions:\n"); - for (i = 1; i <= 5; i++) { - dev_t dev = sysfs_blkdev_partno_to_devno(pc, i); - if (dev) - printf("\t#%d %d:%d\n", i, major(dev), minor(dev)); - } - } - - if (ul_path_read_u64(pc, &u64, "size") != 0) - printf(" (!) read SIZE failed\n"); - else - printf(" SIZE: %jd\n", u64); - - if (ul_path_read_s32(pc, &i, "queue/hw_sector_size")) - printf(" (!) read SECTOR failed\n"); - else - printf(" SECTOR: %d\n", i); - - - chain = sysfs_blkdev_get_devchain(pc, path, sizeof(path)); - printf(" SUBSUSTEMS:\n"); - - while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) { - printf("\t%s\n", sub); - free(sub); - } - - rc = EXIT_SUCCESS; -done: - ul_unref_path(pc); - return rc; -} -#endif /* TEST_PROGRAM_SYSFS */ diff --git a/utils/lib/timer.c b/utils/lib/timer.c deleted file mode 100644 index c1ea54e..0000000 --- a/utils/lib/timer.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Please, don't add this file to libcommon because timers requires - * -lrt on systems with old libc (and probably also -lpthread for static - * build). - */ -#include -#include -#include - -#include "c.h" -#include "timer.h" - -/* - * Note the timeout is used for the first signal, then the signal is send - * repeatedly in interval ~1% of the original timeout to avoid race in signal - * handling -- for example you want to use timer to define timeout for a - * syscall: - * - * setup_timer() - * syscall() - * cancel_timer() - * - * if the timeout is too short than it's possible that the signal is delivered - * before application enter the syscall function. For this reason timer send - * the signal repeatedly. - * - * The applications need to ensure that they can tolerate multiple signal - * deliveries. - */ -#ifdef HAVE_TIMER_CREATE -int setup_timer(struct ul_timer *timer, - struct itimerval *timeout, - void (*timeout_handler)(int, siginfo_t *, void *)) -{ - time_t sec = timeout->it_value.tv_sec; - long usec = timeout->it_value.tv_usec; - struct sigaction sig_a; - static struct sigevent sig_e = { - .sigev_notify = SIGEV_SIGNAL, - .sigev_signo = SIGALRM - }; - struct itimerspec val = { - .it_value.tv_sec = sec, - .it_value.tv_nsec = usec * 1000, - .it_interval.tv_sec = sec / 100, - .it_interval.tv_nsec = (sec ? sec % 100 : 1) * 10*1000*1000 - }; - - if (sigemptyset(&sig_a.sa_mask)) - return 1; - - sig_a.sa_flags = SA_SIGINFO; - sig_a.sa_sigaction = timeout_handler; - - if (sigaction(SIGALRM, &sig_a, NULL)) - return 1; - if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id)) - return 1; - if (timer_settime(timer->t_id, 0, &val, NULL)) - return 1; - return 0; -} -void cancel_timer(struct ul_timer *timer) -{ - timer_delete(timer->t_id); -} - -#else /* !HAVE_TIMER_CREATE */ - -int setup_timer(struct ul_timer *timer, - struct itimerval *timeout, - void (*timeout_handler)(int, siginfo_t *, void *)) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof sa); - memset(timer, 0, sizeof(*timer)); - - sa.sa_flags = SA_SIGINFO | SA_RESETHAND; - sa.sa_sigaction = timeout_handler; - - if (sigaction(SIGALRM, &sa, &timer->old_sa)) - return 1; - if (setitimer(ITIMER_REAL, timeout, &timer->old_timer) != 0) - return 1; - return 0; -} - -void cancel_timer(struct ul_timer *timer) -{ - setitimer(ITIMER_REAL, &timer->old_timer, NULL); - sigaction(SIGALRM, &timer->old_sa, NULL); - -} -#endif /* !HAVE_TIMER_CREATE */ diff --git a/utils/lib/timeutils.c b/utils/lib/timeutils.c deleted file mode 100644 index 8b443cd..0000000 --- a/utils/lib/timeutils.c +++ /dev/null @@ -1,611 +0,0 @@ -/*** - First set of functions in this file are part of systemd, and were - copied to util-linux at August 2013. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with util-linux; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "c.h" -#include "nls.h" -#include "strutils.h" -#include "timeutils.h" - -#define WHITESPACE " \t\n\r" - -#define streq(a,b) (strcmp((a),(b)) == 0) - -static int parse_sec(const char *t, usec_t *usec) -{ - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "seconds", USEC_PER_SEC }, - { "second", USEC_PER_SEC }, - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, - { "minutes", USEC_PER_MINUTE }, - { "minute", USEC_PER_MINUTE }, - { "min", USEC_PER_MINUTE }, - { "months", USEC_PER_MONTH }, - { "month", USEC_PER_MONTH }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "hours", USEC_PER_HOUR }, - { "hour", USEC_PER_HOUR }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "days", USEC_PER_DAY }, - { "day", USEC_PER_DAY }, - { "d", USEC_PER_DAY }, - { "weeks", USEC_PER_WEEK }, - { "week", USEC_PER_WEEK }, - { "w", USEC_PER_WEEK }, - { "years", USEC_PER_YEAR }, - { "year", USEC_PER_YEAR }, - { "y", USEC_PER_YEAR }, - { "usec", 1ULL }, - { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ - }; - - const char *p; - usec_t r = 0; - int something = FALSE; - - assert(t); - assert(usec); - - p = t; - for (;;) { - long long l, z = 0; - char *e; - unsigned i, n = 0; - - p += strspn(p, WHITESPACE); - - if (*p == 0) { - if (!something) - return -EINVAL; - - break; - } - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno > 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (*e == '.') { - char *b = e + 1; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - - if (z < 0) - return -ERANGE; - - if (e == b) - return -EINVAL; - - n = e - b; - - } else if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ARRAY_SIZE(table); i++) - if (startswith(e, table[i].suffix)) { - usec_t k = (usec_t) z * table[i].usec; - - for (; n > 0; n--) - k /= 10; - - r += (usec_t) l *table[i].usec + k; - p = e + strlen(table[i].suffix); - - something = TRUE; - break; - } - - if (i >= ARRAY_SIZE(table)) - return -EINVAL; - - } - - *usec = r; - - return 0; -} - -int parse_timestamp(const char *t, usec_t *usec) -{ - static const struct { - const char *name; - const int nr; - } day_nr[] = { - { "Sunday", 0 }, - { "Sun", 0 }, - { "Monday", 1 }, - { "Mon", 1 }, - { "Tuesday", 2 }, - { "Tue", 2 }, - { "Wednesday", 3 }, - { "Wed", 3 }, - { "Thursday", 4 }, - { "Thu", 4 }, - { "Friday", 5 }, - { "Fri", 5 }, - { "Saturday", 6 }, - { "Sat", 6 }, - }; - - const char *k; - struct tm tm, copy; - time_t x; - usec_t plus = 0, minus = 0, ret; - int r, weekday = -1; - unsigned i; - - /* - * Allowed syntaxes: - * - * 2012-09-22 16:34:22 - * 2012-09-22T16:34:22 - * 2012-09-22 16:34 (seconds will be set to 0) - * 2012-09-22 (time will be set to 00:00:00) - * 16:34:22 (date will be set to today) - * 16:34 (date will be set to today, seconds to 0) - * now - * yesterday (time is set to 00:00:00) - * today (time is set to 00:00:00) - * tomorrow (time is set to 00:00:00) - * +5min - * -5days - * - */ - - assert(t); - assert(usec); - - x = time(NULL); - localtime_r(&x, &tm); - tm.tm_isdst = -1; - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "yesterday")) { - tm.tm_mday--; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "tomorrow")) { - tm.tm_mday++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (t[0] == '+') { - - r = parse_sec(t + 1, &plus); - if (r < 0) - return r; - - goto finish; - } else if (t[0] == '-') { - - r = parse_sec(t + 1, &minus); - if (r < 0) - return r; - - goto finish; - - } else if (endswith(t, " ago")) { - char *z; - - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; - - r = parse_sec(z, &minus); - free(z); - if (r < 0) - return r; - - goto finish; - } - - for (i = 0; i < ARRAY_SIZE(day_nr); i++) { - size_t skip; - - if (!startswith_no_case(t, day_nr[i].name)) - continue; - - skip = strlen(day_nr[i].name); - if (t[skip] != ' ') - continue; - - weekday = day_nr[i].nr; - t += skip + 1; - break; - } - - copy = tm; - k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y%m%d%H%M%S", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - return -EINVAL; - - finish: - x = mktime(&tm); - if (x == (time_t)-1) - return -EINVAL; - - if (weekday >= 0 && tm.tm_wday != weekday) - return -EINVAL; - - ret = (usec_t) x *USEC_PER_SEC; - - ret += plus; - if (ret > minus) - ret -= minus; - else - ret = 0; - - *usec = ret; - - return 0; -} - -/* Returns the difference in seconds between its argument and GMT. If if TP is - * invalid or no DST information is available default to UTC, that is, zero. - * tzset is called so, for example, 'TZ="UTC" hwclock' will work as expected. - * Derived from glibc/time/strftime_l.c - */ -int get_gmtoff(const struct tm *tp) -{ - if (tp->tm_isdst < 0) - return 0; - -#if HAVE_TM_GMTOFF - return tp->tm_gmtoff; -#else - struct tm tm; - struct tm gtm; - struct tm ltm = *tp; - time_t lt; - - tzset(); - lt = mktime(<m); - /* Check if mktime returning -1 is an error or a valid time_t */ - if (lt == (time_t) -1) { - if (! localtime_r(<, &tm) - || ((ltm.tm_sec ^ tm.tm_sec) - | (ltm.tm_min ^ tm.tm_min) - | (ltm.tm_hour ^ tm.tm_hour) - | (ltm.tm_mday ^ tm.tm_mday) - | (ltm.tm_mon ^ tm.tm_mon) - | (ltm.tm_year ^ tm.tm_year))) - return 0; - } - - if (! gmtime_r(<, >m)) - return 0; - - /* Calculate the GMT offset, that is, the difference between the - * TP argument (ltm) and GMT (gtm). - * - * Compute intervening leap days correctly even if year is negative. - * Take care to avoid int overflow in leap day calculations, but it's OK - * to assume that A and B are close to each other. - */ - int a4 = (ltm.tm_year >> 2) + (1900 >> 2) - ! (ltm.tm_year & 3); - int b4 = (gtm.tm_year >> 2) + (1900 >> 2) - ! (gtm.tm_year & 3); - int a100 = a4 / 25 - (a4 % 25 < 0); - int b100 = b4 / 25 - (b4 % 25 < 0); - int a400 = a100 >> 2; - int b400 = b100 >> 2; - int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); - - int years = ltm.tm_year - gtm.tm_year; - int days = (365 * years + intervening_leap_days - + (ltm.tm_yday - gtm.tm_yday)); - - return (60 * (60 * (24 * days + (ltm.tm_hour - gtm.tm_hour)) - + (ltm.tm_min - gtm.tm_min)) + (ltm.tm_sec - gtm.tm_sec)); -#endif -} - -static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf, size_t bufsz) -{ - char *p = buf; - int len; - - if (flags & ISO_DATE) { - len = snprintf(p, bufsz, "%4ld-%.2d-%.2d", - tm->tm_year + (long) 1900, - tm->tm_mon + 1, tm->tm_mday); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if ((flags & ISO_DATE) && (flags & ISO_TIME)) { - if (bufsz < 1) - goto err; - *p++ = (flags & ISO_T) ? 'T' : ' '; - bufsz--; - } - - if (flags & ISO_TIME) { - len = snprintf(p, bufsz, "%02d:%02d:%02d", tm->tm_hour, - tm->tm_min, tm->tm_sec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if (flags & ISO_DOTUSEC) { - len = snprintf(p, bufsz, ".%06ld", (long) usec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - - } else if (flags & ISO_COMMAUSEC) { - len = snprintf(p, bufsz, ",%06ld", (long) usec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if (flags & ISO_TIMEZONE) { - int tmin = get_gmtoff(tm) / 60; - int zhour = tmin / 60; - int zmin = abs(tmin % 60); - len = snprintf(p, bufsz, "%+03d:%02d", zhour,zmin); - if (len < 0 || (size_t) len > bufsz) - goto err; - } - return 0; - err: - warnx(_("format_iso_time: buffer overflow.")); - return -1; -} - -/* timeval to ISO 8601 */ -int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz) -{ - struct tm tm; - struct tm *rc; - - if (flags & ISO_GMTIME) - rc = gmtime_r(&tv->tv_sec, &tm); - else - rc = localtime_r(&tv->tv_sec, &tm); - - if (rc) - return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz); - - warnx(_("time %ld is out of range."), tv->tv_sec); - return -1; -} - -/* struct tm to ISO 8601 */ -int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz) -{ - return format_iso_time(tm, 0, flags, buf, bufsz); -} - -/* time_t to ISO 8601 */ -int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz) -{ - struct tm tm; - struct tm *rc; - - if (flags & ISO_GMTIME) - rc = gmtime_r(t, &tm); - else - rc = localtime_r(t, &tm); - - if (rc) - return format_iso_time(&tm, 0, flags, buf, bufsz); - - warnx(_("time %ld is out of range."), (long)t); - return -1; -} - -/* relative time functions */ -static inline int time_is_thisyear(struct tm const *const tm, - struct tm const *const tmnow) -{ - return tm->tm_year == tmnow->tm_year; -} - -static inline int time_is_today(struct tm const *const tm, - struct tm const *const tmnow) -{ - return (tm->tm_yday == tmnow->tm_yday && - time_is_thisyear(tm, tmnow)); -} - -int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, size_t bufsz) -{ - struct tm tm, tmnow; - int rc = 0; - - if (now->tv_sec == 0) - gettimeofday(now, NULL); - - localtime_r(t, &tm); - localtime_r(&now->tv_sec, &tmnow); - - if (time_is_today(&tm, &tmnow)) { - rc = snprintf(buf, bufsz, "%02d:%02d", tm.tm_hour, tm.tm_min); - if (rc < 0 || (size_t) rc > bufsz) - return -1; - rc = 1; - - } else if (time_is_thisyear(&tm, &tmnow)) { - if (flags & UL_SHORTTIME_THISYEAR_HHMM) - rc = strftime(buf, bufsz, "%b%d/%H:%M", &tm); - else - rc = strftime(buf, bufsz, "%b%d", &tm); - } else - rc = strftime(buf, bufsz, "%Y-%b%d", &tm); - - return rc <= 0 ? -1 : 0; -} - -#ifndef HAVE_TIMEGM -time_t timegm(struct tm *tm) -{ - const char *zone = getenv("TZ"); - time_t ret; - - setenv("TZ", "", 1); - tzset(); - ret = mktime(tm); - if (zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); - tzset(); - return ret; -} -#endif /* HAVE_TIMEGM */ - -#ifdef TEST_PROGRAM_TIMEUTILS - -int main(int argc, char *argv[]) -{ - struct timeval tv = { 0 }; - char buf[ISO_BUFSIZ]; - - if (argc < 2) { - fprintf(stderr, "usage: %s [