diff options
author | Manuel Bentele | 2020-12-02 13:08:58 +0100 |
---|---|---|
committer | Manuel Bentele | 2020-12-02 13:08:58 +0100 |
commit | 9fc030ed9bffec9f9715595dd5a205a353912d3c (patch) | |
tree | 8137142e94abf7cd4eefd3b591c487d034b57e50 /src | |
parent | Setup xloop device with XLOOP_CONFIGURE ioctl call (diff) | |
download | xloop-9fc030ed9bffec9f9715595dd5a205a353912d3c.tar.gz xloop-9fc030ed9bffec9f9715595dd5a205a353912d3c.tar.xz xloop-9fc030ed9bffec9f9715595dd5a205a353912d3c.zip |
Update xlosetup's 'lib' and 'libsmartcol' from util-linux 2.36.1
Diffstat (limited to 'src')
35 files changed, 871 insertions, 325 deletions
diff --git a/src/utils/config.h b/src/utils/config.h index 781ddc7..35ec9d5 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -288,6 +288,9 @@ /* Define to 1 if you have the <linux/fd.h> header file. */ #define HAVE_LINUX_FD_H 1 +/* Define to 1 if you have the <linux/fiemap.h> header file. */ +#define HAVE_LINUX_FIEMAP_H 1 + /* Define to 1 if you have the <linux/fs.h> header file. */ /* #undef HAVE_LINUX_FS_H */ @@ -450,6 +453,9 @@ /* Define to 1 if you have the <security/pam_misc.h> header file. */ #define HAVE_SECURITY_PAM_MISC_H 1 +/* Define to 1 if you have the `sendfile' function. */ +#define HAVE_SENDFILE 1 + /* Define to 1 if you have the `setitimer' function. */ /* #undef HAVE_SETITIMER */ @@ -576,6 +582,9 @@ /* Define to 1 if you have the <sys/resource.h> header file. */ #define HAVE_SYS_RESOURCE_H 1 +/* Define to 1 if you have the <sys/sendfile.h> header file. */ +#define HAVE_SYS_SENDFILE_H 1 + /* Define to 1 if you have the <sys/signalfd.h> header file. */ #define HAVE_SYS_SIGNALFD_H 1 diff --git a/src/utils/include/all-io.h b/src/utils/include/all-io.h index 8ffa9cf..5ed2d11 100644 --- a/src/utils/include/all-io.h +++ b/src/utils/include/all-io.h @@ -12,6 +12,10 @@ #include <string.h> #include <unistd.h> #include <errno.h> +#include <sys/types.h> +#ifdef HAVE_SYS_SENDFILE_H +# include <sys/sendfile.h> +#endif #include "c.h" @@ -63,13 +67,15 @@ static inline ssize_t read_all(int fd, char *buf, size_t count) memset(buf, 0, count); while (count > 0) { ret = read(fd, buf, count); - if (ret <= 0) { - if (ret < 0 && (errno == EAGAIN || errno == EINTR) && (tries++ < 5)) { + if (ret < 0) { + if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) { xusleep(250000); continue; } return c ? c : -1; } + if (ret == 0) + return c; tries = 0; count -= ret; buf += ret; @@ -78,4 +84,32 @@ static inline ssize_t read_all(int fd, char *buf, size_t count) return c; } +static inline ssize_t sendfile_all(int out, int in, off_t *off, size_t count) +{ +#if defined(HAVE_SENDFILE) && defined(__linux__) + ssize_t ret; + ssize_t c = 0; + int tries = 0; + while (count) { + ret = sendfile(out, in, off, count); + if (ret < 0) { + if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) { + xusleep(250000); + continue; + } + return c ? c : -1; + } + if (ret == 0) + return c; + tries = 0; + count -= ret; + c += ret; + } + return c; +#else + errno = ENOSYS; + return -1; +#endif +} + #endif /* UTIL_LINUX_ALL_IO_H */ diff --git a/src/utils/include/buffer.h b/src/utils/include/buffer.h new file mode 100644 index 0000000..5bc7037 --- /dev/null +++ b/src/utils/include/buffer.h @@ -0,0 +1,28 @@ +#ifndef UTIL_LINUX_BUFFER +#define UTIL_LINUX_BUFFER + +#include "c.h" + +struct ul_buffer { + char *begin; /* begin of the data */ + char *end; /* current end of data */ + + size_t sz; /* allocated space for data */ + size_t chunksize; +}; + +#define UL_INIT_BUFFER { .begin = NULL } + +void ul_buffer_reset_data(struct ul_buffer *buf); +void ul_buffer_free_data(struct ul_buffer *buf); +int ul_buffer_is_empty(struct ul_buffer *buf); +void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz); +void ul_buffer_refer_string(struct ul_buffer *buf, char *str); +int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz); +int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz); +int ul_buffer_append_string(struct ul_buffer *buf, const char *str); +int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str); +int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz); +char *ul_buffer_get_data(struct ul_buffer *buf); + +#endif /* UTIL_LINUX_BUFFER */ diff --git a/src/utils/include/fileutils.h b/src/utils/include/fileutils.h index 479ad15..618bf39 100644 --- a/src/utils/include/fileutils.h +++ b/src/utils/include/fileutils.h @@ -74,4 +74,8 @@ static inline struct dirent *xreaddir(DIR *dp) extern void close_all_fds(const int exclude[], size_t exsz); +#define UL_COPY_READ_ERROR (-1) +#define UL_COPY_WRITE_ERROR (-2) +int ul_copy_file(int from, int to); + #endif /* UTIL_LINUX_FILEUTILS */ diff --git a/src/utils/include/jsonwrt.h b/src/utils/include/jsonwrt.h new file mode 100644 index 0000000..04ef49e --- /dev/null +++ b/src/utils/include/jsonwrt.h @@ -0,0 +1,44 @@ +#ifndef UTIL_LINUX_JSONWRT_H +#define UTIL_LINUX_JSONWRT_H + +enum { + UL_JSON_OBJECT, + UL_JSON_ARRAY, + UL_JSON_VALUE +}; + +struct ul_jsonwrt { + FILE *out; + int indent; + + unsigned int postponed_break :1; +}; + +void ul_jsonwrt_init(struct ul_jsonwrt *fmt, FILE *out, int indent); +void ul_jsonwrt_indent(struct ul_jsonwrt *fmt); +void ul_jsonwrt_open(struct ul_jsonwrt *fmt, const char *name, int type); +void ul_jsonwrt_close(struct ul_jsonwrt *fmt, int type, int islast); + +#define ul_jsonwrt_root_open(_f) ul_jsonwrt_open(_f, NULL, UL_JSON_OBJECT) +#define ul_jsonwrt_root_close(_f) ul_jsonwrt_close(_f, UL_JSON_OBJECT, 1) + +#define ul_jsonwrt_array_open(_f, _n) ul_jsonwrt_open(_f, _n, UL_JSON_ARRAY) +#define ul_jsonwrt_array_close(_f, _l) ul_jsonwrt_close(_f, UL_JSON_ARRAY, _l) + +#define ul_jsonwrt_object_open(_f, _n) ul_jsonwrt_open(_f, _n, UL_JSON_OBJECT) +#define ul_jsonwrt_object_close(_f, _l) ul_jsonwrt_close(_f, UL_JSON_OBJECT, _l) + +#define ul_jsonwrt_value_open(_f, _n) ul_jsonwrt_open(_f, _n, UL_JSON_VALUE) +#define ul_jsonwrt_value_close(_f, _l) ul_jsonwrt_close(_f, UL_JSON_VALUE, _l) + + +void ul_jsonwrt_value_raw(struct ul_jsonwrt *fmt, + const char *name, const char *data, int islast); +void ul_jsonwrt_value_s(struct ul_jsonwrt *fmt, + const char *name, const char *data, int islast); +void ul_jsonwrt_value_u64(struct ul_jsonwrt *fmt, + const char *name, uint64_t data, int islast); +void ul_jsonwrt_value_boolean(struct ul_jsonwrt *fmt, + const char *name, int data, int islast); + +#endif /* UTIL_LINUX_JSONWRT_H */ diff --git a/src/utils/include/loopdev.h b/src/utils/include/loopdev.h index 9fa0688..0184ffe 100644 --- a/src/utils/include/loopdev.h +++ b/src/utils/include/loopdev.h @@ -156,6 +156,7 @@ extern int is_loopdev(const char *device); extern int loopdev_is_autoclear(const char *device); extern char *loopdev_get_backing_file(const char *device); +extern int loopdev_has_backing_file(const char *device); extern int loopdev_is_used(const char *device, const char *filename, uint64_t offset, uint64_t sizelimit, int flags); extern char *loopdev_find_by_backing_file(const char *filename, diff --git a/src/utils/include/procutils.h b/src/utils/include/procutils.h index 9f8dd76..c9f5bb5 100644 --- a/src/utils/include/procutils.h +++ b/src/utils/include/procutils.h @@ -2,6 +2,7 @@ #define UTIL_LINUX_PROCUTILS #include <dirent.h> +#include <sys/types.h> struct proc_tasks { DIR *dir; @@ -31,4 +32,6 @@ extern int proc_next_pid(struct proc_processes *ps, pid_t *pid); extern char *proc_get_command(pid_t pid); extern char *proc_get_command_name(pid_t pid); +extern int proc_is_procfs(int fd); + #endif /* UTIL_LINUX_PROCUTILS */ diff --git a/src/utils/include/pt-gpt-partnames.h b/src/utils/include/pt-gpt-partnames.h index 604f2c6..6c54a71 100644 --- a/src/utils/include/pt-gpt-partnames.h +++ b/src/utils/include/pt-gpt-partnames.h @@ -50,8 +50,8 @@ DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")), DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")), DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")), DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")), -DEF_GUID("69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", N_("Linux root (ARM)")), DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")), +DEF_GUID("69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", N_("Linux root (ARM)")), DEF_GUID("B921B045-1DF0-41C3-AF44-4C6F280D3FAE", N_("Linux root (ARM-64)")), DEF_GUID("993D8D3D-F80E-4225-855A-9DAF8ED7EA97", N_("Linux root (IA-64)")), DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")), @@ -60,11 +60,21 @@ DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")), DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")), DEF_GUID("4D21B016-B534-45C2-A9FB-5C16E091FD2D", N_("Linux variable data")), DEF_GUID("7EC6F557-3BC5-4ACA-B293-16EF5DF639D1", N_("Linux temporary data")), +DEF_GUID("75250D76-8CC6-458E-BD66-BD47CC81A812", N_("Linux /usr (x86)")), +DEF_GUID("8484680C-9521-48C6-9C11-B0720656F69E", N_("Linux /usr (x86-64)")), +DEF_GUID("7D0359A3-02B3-4F0A-865C-654403E70625", N_("Linux /usr (ARM)")), +DEF_GUID("B0E01050-EE5F-4390-949A-9101B17104E9", N_("Linux /usr (ARM-64)")), +DEF_GUID("4301D2A6-4E3B-4B2A-BB94-9E0B2C4225EA", N_("Linux /usr (IA-64)")), DEF_GUID("D13C5D3B-B5D1-422A-B29F-9454FDC89D76", N_("Linux root verity (x86)")), -DEF_GUID("7386CDF2-203C-47A9-A498-F2ECCE45A2D6", N_("Linux root verity (ARM)")), DEF_GUID("2C7357ED-EBD2-46D9-AEC1-23D437EC2BF5", N_("Linux root verity (x86-64)")), +DEF_GUID("7386CDF2-203C-47A9-A498-F2ECCE45A2D6", N_("Linux root verity (ARM)")), DEF_GUID("DF3300CE-D69F-4C92-978C-9BFB0F38D820", N_("Linux root verity (ARM-64)")), DEF_GUID("86ED10D5-B607-45BB-8957-D350F23D0571", N_("Linux root verity (IA-64)")), +DEF_GUID("8F461B0D-14EE-4E81-9AA9-049B6FB97ABD", N_("Linux /usr verity (x86)")), +DEF_GUID("77FF5F63-E7B6-4633-ACF4-1565B864C0E6", N_("Linux /usr verity (x86-64)")), +DEF_GUID("C215D751-7BCD-4649-BE90-6627490A4C05", N_("Linux /usr verity (ARM)")), +DEF_GUID("6E11A4E7-FBCA-4DED-B9E9-E1A512BB664E", N_("Linux /usr verity (ARM-64)")), +DEF_GUID("6A491E03-3BE7-4545-8E38-83320E0EA880", N_("Linux /usr verity (IA-64)")), /* ... too crazy, ignore for now: DEF_GUID("7FFEC5C9-2D00-49B7-8941-3EA10A5586B7", N_("Linux plain dm-crypt")), DEF_GUID("CA7D7CCB-63ED-4C53-861C-1742536059CC", N_("Linux LUKS")), diff --git a/src/utils/include/randutils.h b/src/utils/include/randutils.h index 86e35f3..690bf5e 100644 --- a/src/utils/include/randutils.h +++ b/src/utils/include/randutils.h @@ -11,7 +11,7 @@ extern int rand_get_number(int low_n, int high_n); /* /dev/urandom based with fallback to rand() */ extern int random_get_fd(void); -extern void random_get_bytes(void *buf, size_t nbytes); +extern int ul_random_get_bytes(void *buf, size_t nbytes); extern const char *random_tell_source(void); #endif diff --git a/src/utils/include/strutils.h b/src/utils/include/strutils.h index 4b3182f..09cc35e 100644 --- a/src/utils/include/strutils.h +++ b/src/utils/include/strutils.h @@ -9,6 +9,8 @@ #include <stdio.h> #include <errno.h> +#include "c.h" + /* initialize a custom exit code for all *_or_err functions */ extern void strutils_set_exitcode(int exit_code); @@ -61,8 +63,13 @@ extern char *strnchr(const char *s, size_t maxlen, int c); /* caller guarantees n > 0 */ static inline void xstrncpy(char *dest, const char *src, size_t n) { - strncpy(dest, src, n-1); - dest[n-1] = 0; + size_t len = src ? strlen(src) : 0; + + if (!len) + return; + len = min(len, n - 1); + memcpy(dest, src, len); + dest[len] = 0; } /* This is like strncpy(), but based on memcpy(), so compilers and static @@ -303,6 +310,33 @@ static inline size_t ltrim_whitespace(unsigned char *str) return len; } +/* Removes left-hand, right-hand and repeating whitespaces. + */ +static inline size_t normalize_whitespace(unsigned char *str) +{ + size_t i, x, sz = strlen((char *) str); + int nsp = 0, intext = 0; + + if (!sz) + return 0; + + for (i = 0, x = 0; i < sz; ) { + if (isspace(str[i])) + nsp++; + else + nsp = 0, intext = 1; + + if (nsp > 1 || (nsp && !intext)) + i++; + else + str[x++] = str[i++]; + } + if (nsp) /* tailing space */ + x--; + str[x] = '\0'; + return x; +} + static inline void strrep(char *s, int find, int replace) { while (s && *s && (s = strchr(s, find)) != NULL) diff --git a/src/utils/include/swapheader.h b/src/utils/include/swapheader.h deleted file mode 100644 index 3fce0d0..0000000 --- a/src/utils/include/swapheader.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SWAPHEADER_H -#define _SWAPHEADER_H - -#define SWAP_VERSION 1 -#define SWAP_UUID_LENGTH 16 -#define SWAP_LABEL_LENGTH 16 -#define SWAP_SIGNATURE "SWAPSPACE2" -#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1) - -#include <stdint.h> - -struct swap_header_v1_2 { - char bootbits[1024]; /* Space for disklabel etc. */ - uint32_t version; - uint32_t last_page; - uint32_t nr_badpages; - unsigned char uuid[SWAP_UUID_LENGTH]; - char volume_name[SWAP_LABEL_LENGTH]; - uint32_t padding[117]; - uint32_t badpages[1]; -}; - -#endif /* _SWAPHEADER_H */ diff --git a/src/utils/include/swapprober.h b/src/utils/include/swapprober.h deleted file mode 100644 index 5107700..0000000 --- a/src/utils/include/swapprober.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UTIL_LINUX_SWAP_PROBER_H -#define UTIL_LINUX_SWAP_PROBER_H - -#include <blkid.h> - -blkid_probe get_swap_prober(const char *devname); - -#endif /* UTIL_LINUX_SWAP_PROBER_H */ - diff --git a/src/utils/lib/CMakeLists.txt b/src/utils/lib/CMakeLists.txt index ac70039..1a92d32 100644 --- a/src/utils/lib/CMakeLists.txt +++ b/src/utils/lib/CMakeLists.txt @@ -5,6 +5,7 @@ project(xloop-utils-lib LANGUAGES C) add_library(libcommon STATIC ${CMAKE_CURRENT_SOURCE_DIR}/blkdev.c + ${CMAKE_CURRENT_SOURCE_DIR}/buffer.c ${CMAKE_CURRENT_SOURCE_DIR}/canonicalize.c ${CMAKE_CURRENT_SOURCE_DIR}/caputils.c ${CMAKE_CURRENT_SOURCE_DIR}/color-names.c @@ -18,6 +19,7 @@ add_library(libcommon STATIC ${CMAKE_CURRENT_SOURCE_DIR}/blkdev.c ${CMAKE_CURRENT_SOURCE_DIR}/fileutils.c ${CMAKE_CURRENT_SOURCE_DIR}/idcache.c ${CMAKE_CURRENT_SOURCE_DIR}/ismounted.c + ${CMAKE_CURRENT_SOURCE_DIR}/jsonwrt.c ${CMAKE_CURRENT_SOURCE_DIR}/langinfo.c ${CMAKE_CURRENT_SOURCE_DIR}/linux_version.c ${CMAKE_CURRENT_SOURCE_DIR}/loopdev.c diff --git a/src/utils/lib/buffer.c b/src/utils/lib/buffer.c new file mode 100644 index 0000000..2658211 --- /dev/null +++ b/src/utils/lib/buffer.c @@ -0,0 +1,162 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#include "buffer.h" + +void ul_buffer_reset_data(struct ul_buffer *buf) +{ + if (buf->begin) + buf->begin[0] = '\0'; + buf->end = buf->begin; +} + +void ul_buffer_free_data(struct ul_buffer *buf) +{ + assert(buf); + + free(buf->begin); + buf->begin = NULL; + buf->end = NULL; + buf->sz = 0; +} + +void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz) +{ + buf->chunksize = sz; +} + +int ul_buffer_is_empty(struct ul_buffer *buf) +{ + return buf->begin == buf->end; +} + +void ul_buffer_refer_string(struct ul_buffer *buf, char *str) +{ + if (buf->sz) + ul_buffer_free_data(buf); + buf->begin = str; + buf->sz = str ? strlen(str) : 0; + buf->end = buf->begin ? buf->begin + buf->sz : buf->begin; +} + +int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz) +{ + char *tmp; + size_t len = 0; + + assert(buf); + + if (sz <= buf->sz) + return 0; + + if (buf->end && buf->begin) + len = buf->end - buf->begin; + + if (buf->chunksize) + sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1; + + tmp = realloc(buf->begin, sz); + if (!tmp) + return -ENOMEM; + + buf->begin = tmp; + buf->end = buf->begin + len; + buf->sz = sz; + + return 0; +} + +int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz) +{ + size_t maxsz = 0; + + if (!buf) + return -EINVAL; + if (!data || !*data) + return 0; + + if (buf->begin && buf->end) + maxsz = buf->sz - (buf->end - buf->begin); + + if (maxsz <= sz + 1) { + int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1); + if (rc) + return rc; + } + if (!buf->end) + return -EINVAL; /* make static analyzers happy */ + + memcpy(buf->end, data, sz); + buf->end += sz; + *buf->end = '\0'; /* make sure it's terminated */ + return 0; +} + +int ul_buffer_append_string(struct ul_buffer *buf, const char *str) +{ + return ul_buffer_append_data(buf, str, strlen(str)); +} + +int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str) +{ + size_t i; + size_t len = strlen(str); + + for (i = 0; len && i < n; i++) { + int rc = ul_buffer_append_data(buf, str, len); + if (rc) + return rc; + } + return 0; +} + +int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz) +{ + ul_buffer_reset_data(buf); + return ul_buffer_append_data(buf, data, sz); +} + +char *ul_buffer_get_data(struct ul_buffer *buf) +{ + return buf->begin; +} + +#ifdef TEST_PROGRAM_BUFFER +int main(void) +{ + struct ul_buffer buf = UL_INIT_BUFFER; + char *str; + + ul_buffer_set_chunksize(&buf, 16); + + ul_buffer_append_string(&buf, "AAA"); + ul_buffer_append_data(&buf, "=", 1); + ul_buffer_append_string(&buf, "aaa"); + ul_buffer_append_data(&buf, ",", 1); + ul_buffer_append_string(&buf, "BBB"); + ul_buffer_append_string(&buf, "="); + ul_buffer_append_string(&buf, "bbb"); + + str = ul_buffer_get_data(&buf); + printf("data '%s'\n", str); + + ul_buffer_reset_data(&buf); + ul_buffer_append_string(&buf, "This is really long string to test the buffer function."); + ul_buffer_append_string(&buf, " YES!"); + str = ul_buffer_get_data(&buf); + printf("data '%s'\n", str); + + ul_buffer_free_data(&buf); + str = strdup("foo"); + ul_buffer_refer_string(&buf, str); + ul_buffer_append_data(&buf, ",", 1); + ul_buffer_append_string(&buf, "bar"); + str = ul_buffer_get_data(&buf); + printf("data '%s'\n", str); + + ul_buffer_free_data(&buf); +} +#endif /* TEST_PROGRAM_BUFFER */ diff --git a/src/utils/lib/caputils.c b/src/utils/lib/caputils.c index 17e9c01..13a376b 100644 --- a/src/utils/lib/caputils.c +++ b/src/utils/lib/caputils.c @@ -14,32 +14,105 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <sys/prctl.h> #include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include "c.h" #include "caputils.h" +#include "procutils.h" #include "pathnames.h" +static int test_cap(unsigned int cap) +{ + /* prctl returns 0 or 1 for valid caps, -1 otherwise */ + return prctl(PR_CAPBSET_READ, cap, 0, 0, 0) >= 0; +} + +static int cap_last_by_bsearch(int *ret) +{ + /* starting with cap=INT_MAX means we always know + * that cap1 is invalid after the first iteration */ + int cap = INT_MAX; + unsigned int cap0 = 0, cap1 = INT_MAX; + + while ((int)cap0 < cap) { + if (test_cap(cap)) + cap0 = cap; + else + cap1 = cap; + + cap = (cap0 + cap1) / 2U; + } + + *ret = cap; + return 0; +} + +static int cap_last_by_procfs(int *ret) +{ + FILE *f = fopen(_PATH_PROC_CAPLASTCAP, "r"); + int rc = -EINVAL; + + *ret = 0; + + if (f && proc_is_procfs(fileno(f))) { + int cap; + + /* we check if the cap after this one really isn't valid */ + if (fscanf(f, "%d", &cap) == 1 && + cap < INT_MAX && !test_cap(cap + 1)) { + + *ret = cap; + rc = 0; + } + } + + if (f) + fclose(f); + return rc; +} + 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; + static int cap = -1; + + if (cap != -1) + return cap; + if (cap_last_by_procfs(&cap) < 0) + cap_last_by_bsearch(&cap); + + return cap; +} + +#ifdef TEST_PROGRAM_CAPUTILS +int main(int argc, char *argv[]) +{ + int rc = 0, cap; + + if (argc < 2) { + fprintf(stderr, "usage: %1$s --last-by-procfs\n" + " %1$s --last-by-bsearch\n" + " %1$s --last\n", + program_invocation_short_name); + return EXIT_FAILURE; } - matched = fscanf(f, "%d", &ret); - fclose(f); + if (strcmp(argv[1], "--last-by-procfs") == 0) { + rc = cap_last_by_procfs(&cap); + if (rc == 0) + printf("last cap: %d\n", cap); + + } else if (strcmp(argv[1], "--last-by-bsearch") == 0) { + rc = cap_last_by_bsearch(&cap); + if (rc == 0) + printf("last cap: %d\n", cap); - if (matched != 1) - ret = CAP_LAST_CAP; /* guess */ + } else if (strcmp(argv[1], "--last") == 0) + printf("last cap: %d\n", cap_last_cap()); - return ret; + return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } +#endif diff --git a/src/utils/lib/env.c b/src/utils/lib/env.c index c26a5be..ac481ee 100644 --- a/src/utils/lib/env.c +++ b/src/utils/lib/env.c @@ -1,10 +1,9 @@ /* - * Security checks of environment - * Added from shadow-utils package - * by Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> + * environ[] array cleanup code and getenv() wrappers * + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. */ - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -57,7 +56,7 @@ struct ul_env_list { }; /* - * Saves @name env.varable to @ls, returns pointer to the new head of the list. + * Saves @name env.variable 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) { diff --git a/src/utils/lib/exec_shell.c b/src/utils/lib/exec_shell.c index 18798eb..6fef6c7 100644 --- a/src/utils/lib/exec_shell.c +++ b/src/utils/lib/exec_shell.c @@ -46,6 +46,6 @@ void __attribute__((__noreturn__)) exec_shell(void) arg0[0] = '-'; strcpy(arg0 + 1, shell_basename); - execl(shell, arg0, NULL); + execl(shell, arg0, (char *)NULL); errexec(shell); } diff --git a/src/utils/lib/fileutils.c b/src/utils/lib/fileutils.c index 3ca43c1..9da906a 100644 --- a/src/utils/lib/fileutils.c +++ b/src/utils/lib/fileutils.c @@ -1,15 +1,20 @@ /* + * This code is in the public domain; do with it what you wish. + * * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> + * Copyright (C) 2012-2020 Karel Zak <kzak@redhat.com> */ - #include <stdio.h> #include <stdlib.h> +#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <sys/time.h> #include <sys/resource.h> +#include <string.h> #include "c.h" +#include "all-io.h" #include "fileutils.h" #include "pathnames.h" @@ -172,7 +177,7 @@ void close_all_fds(const int exclude[], size_t exsz) int main(int argc, char *argv[]) { if (argc < 2) - errx(EXIT_FAILURE, "Usage %s --{mkstemp,close-fds}", argv[0]); + errx(EXIT_FAILURE, "Usage %s --{mkstemp,close-fds,copy-file}", argv[0]); if (strcmp(argv[1], "--mkstemp") == 0) { FILE *f; @@ -192,6 +197,12 @@ int main(int argc, char *argv[]) ignore_result( dup(STDIN_FILENO) ); close_all_fds(wanted_fds, ARRAY_SIZE(wanted_fds)); + } else if (strcmp(argv[1], "--copy-file") == 0) { + int ret = ul_copy_file(STDIN_FILENO, STDOUT_FILENO); + if (ret == UL_COPY_READ_ERROR) + err(EXIT_FAILURE, "read"); + else if (ret == UL_COPY_WRITE_ERROR) + err(EXIT_FAILURE, "write"); } return EXIT_SUCCESS; } @@ -244,3 +255,42 @@ char *stripoff_last_component(char *path) *p = '\0'; return p + 1; } + +static int copy_file_simple(int from, int to) +{ + ssize_t nr; + char buf[BUFSIZ]; + + while ((nr = read_all(from, buf, sizeof(buf))) > 0) + if (write_all(to, buf, nr) == -1) + return UL_COPY_WRITE_ERROR; + if (nr < 0) + return UL_COPY_READ_ERROR; +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(buf, sizeof(buf)); +#endif + return 0; +} + +/* Copies the contents of a file. Returns -1 on read error, -2 on write error. */ +int ul_copy_file(int from, int to) +{ +#ifdef HAVE_SENDFILE + struct stat st; + ssize_t nw; + + if (fstat(from, &st) == -1) + return UL_COPY_READ_ERROR; + if (!S_ISREG(st.st_mode)) + return copy_file_simple(from, to); + if (sendfile_all(to, from, NULL, st.st_size) < 0) + return copy_file_simple(from, to); + /* ensure we either get an EOF or an error */ + while ((nw = sendfile_all(to, from, NULL, 16*1024*1024)) != 0) + if (nw < 0) + return copy_file_simple(from, to); + return 0; +#else + return copy_file_simple(from, to); +#endif +} diff --git a/src/utils/lib/jsonwrt.c b/src/utils/lib/jsonwrt.c new file mode 100644 index 0000000..00e8b9d --- /dev/null +++ b/src/utils/lib/jsonwrt.c @@ -0,0 +1,128 @@ +/* + * JSON output formatting functions. + * + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#include <stdio.h> +#include <inttypes.h> + +#include "c.h" +#include "carefulputc.h" +#include "jsonwrt.h" + + +void ul_jsonwrt_init(struct ul_jsonwrt *fmt, FILE *out, int indent) +{ + fmt->out = out; + fmt->indent = indent; +} + +void ul_jsonwrt_indent(struct ul_jsonwrt *fmt) +{ + int i; + + for (i = 0; i < fmt->indent; i++) + fputs(" ", fmt->out); +} + +void ul_jsonwrt_open(struct ul_jsonwrt *fmt, const char *name, int type) +{ + if (fmt->postponed_break && !name) + ; + else { + ul_jsonwrt_indent(fmt); + if (name) + fputs_quoted_json_lower(name, fmt->out); + } + + switch (type) { + case UL_JSON_OBJECT: + fputs(name ? ": {\n" : "{\n", fmt->out); + fmt->indent++; + break; + case UL_JSON_ARRAY: + fputs(name ? ": [\n" : "{\n", fmt->out); + fmt->indent++; + break; + case UL_JSON_VALUE: + fputs(name ? ": " : " ", fmt->out); + break; + } + fmt->postponed_break = 0; +} + +void ul_jsonwrt_close(struct ul_jsonwrt *fmt, int type, int islast) +{ + if (fmt->indent == 0) { + fputs("}\n", fmt->out); + fmt->indent--; + return; + } + assert(fmt->indent > 0); + + switch (type) { + case UL_JSON_OBJECT: + fmt->indent--; + ul_jsonwrt_indent(fmt); + fputs(islast ? "}" : "},", fmt->out); + break; + case UL_JSON_ARRAY: + fmt->indent--; + ul_jsonwrt_indent(fmt); + fputs(islast ? "]" : "],", fmt->out); + break; + case UL_JSON_VALUE: + if (!islast) + fputc(',', fmt->out); + break; + } + + if (!islast && (type == UL_JSON_OBJECT || type == UL_JSON_ARRAY)) + fmt->postponed_break = 1; + else { + fputc('\n', fmt->out); + fmt->postponed_break = 0; + } +} + +void ul_jsonwrt_value_raw(struct ul_jsonwrt *fmt, + const char *name, const char *data, int islast) +{ + ul_jsonwrt_value_open(fmt, name); + if (data && *data) + fputs(data, fmt->out); + else + fputs("null", fmt->out); + ul_jsonwrt_value_close(fmt, islast); +} + +void ul_jsonwrt_value_s(struct ul_jsonwrt *fmt, + const char *name, const char *data, int islast) +{ + ul_jsonwrt_value_open(fmt, name); + if (data && *data) + fputs_quoted_json(data, fmt->out); + else + fputs("null", fmt->out); + ul_jsonwrt_value_close(fmt, islast); +} + +void ul_jsonwrt_value_u64(struct ul_jsonwrt *fmt, + const char *name, uint64_t data, int islast) +{ + ul_jsonwrt_value_open(fmt, name); + fprintf(fmt->out, "%"PRIu64, data); + ul_jsonwrt_value_close(fmt, islast); +} + +void ul_jsonwrt_value_boolean(struct ul_jsonwrt *fmt, + const char *name, int data, int islast) +{ + ul_jsonwrt_value_open(fmt, name); + fputs(data ? "true" : "false", fmt->out); + ul_jsonwrt_value_close(fmt, islast); +} + diff --git a/src/utils/lib/linux_version.c b/src/utils/lib/linux_version.c index 137bbe7..119869e 100644 --- a/src/utils/lib/linux_version.c +++ b/src/utils/lib/linux_version.c @@ -1,3 +1,7 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ #include <stdio.h> #include <sys/utsname.h> diff --git a/src/utils/lib/pager.c b/src/utils/lib/pager.c index b3cf6ee..747521e 100644 --- a/src/utils/lib/pager.c +++ b/src/utils/lib/pager.c @@ -88,14 +88,14 @@ static int start_command(struct child_process *cmd) if (cmd->pid < 0) { if (need_in) close_pair(fdin); - else if (cmd->in) + else if (0 <= cmd->in) close(cmd->in); return -1; } if (need_in) close(fdin[0]); - else if (cmd->in) + else if (0 <= cmd->in) close(cmd->in); return 0; } diff --git a/src/utils/lib/procutils.c b/src/utils/lib/procutils.c index 8fb5d5c..bf689ab 100644 --- a/src/utils/lib/procutils.c +++ b/src/utils/lib/procutils.c @@ -1,17 +1,11 @@ /* * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org> + * Copyright (C) 2011-2020 Karel Zak <kzak@redhat.com> * * 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. + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. */ #include <stdio.h> @@ -19,11 +13,13 @@ #include <string.h> #include <errno.h> #include <sys/stat.h> +#include <sys/vfs.h> #include <sys/types.h> #include <dirent.h> #include <ctype.h> #include "procutils.h" +#include "statfs_magic.h" #include "fileutils.h" #include "all-io.h" #include "c.h" @@ -241,6 +237,27 @@ int proc_next_pid(struct proc_processes *ps, pid_t *pid) return 0; } +/* checks if fd is file in a procfs; + * returns 1 if true, 0 if false or couldn't determine */ +int proc_is_procfs(int fd) +{ + struct statfs st; + int ret; + + do { + errno = 0; + ret = fstatfs(fd, &st); + + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return 0; + xusleep(250000); + } + } while (ret != 0); + + return st.f_type == STATFS_PROC_MAGIC; +} + #ifdef TEST_PROGRAM_PROCUTILS static int test_tasks(int argc, char *argv[]) @@ -289,10 +306,28 @@ static int test_processes(int argc, char *argv[]) return EXIT_SUCCESS; } +static int test_isprocfs(int argc, char *argv[]) +{ + const char *name = argc > 1 ? argv[1] : "/proc"; + int fd = open(name, O_RDONLY); + int is = 0; + + if (fd >= 0) { + is = proc_is_procfs(fd); + close(fd); + } else + err(EXIT_FAILURE, "cannot open %s", name); + + printf("%s: %s procfs\n", name, is ? "is" : "is NOT"); + return is ? EXIT_SUCCESS : EXIT_FAILURE; +} + + int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "usage: %1$s --tasks <pid>\n" + " %1$s --is-procfs [<dir>]\n" " %1$s --processes [---name <name>] [--uid <uid>]\n", program_invocation_short_name); return EXIT_FAILURE; @@ -302,6 +337,8 @@ int main(int argc, char *argv[]) return test_tasks(argc - 1, argv + 1); if (strcmp(argv[1], "--processes") == 0) return test_processes(argc - 1, argv + 1); + if (strcmp(argv[1], "--is-procfs") == 0) + return test_isprocfs(argc - 1, argv + 1); return EXIT_FAILURE; } diff --git a/src/utils/lib/pty-session.c b/src/utils/lib/pty-session.c index 06b2a49..f4bb004 100644 --- a/src/utils/lib/pty-session.c +++ b/src/utils/lib/pty-session.c @@ -340,12 +340,17 @@ static int handle_io(struct ul_pty *pty, int fd, int *eof) char buf[BUFSIZ]; ssize_t bytes; int rc = 0; + sigset_t set; DBG(IO, ul_debugobj(pty, " handle I/O on fd=%d", fd)); *eof = 0; + sigemptyset(&set); + sigaddset(&set, SIGTTIN); + sigprocmask(SIG_UNBLOCK, &set, NULL); /* read from active FD */ bytes = read(fd, buf, sizeof(buf)); + sigprocmask(SIG_BLOCK, &set, NULL); if (bytes < 0) { if (errno == EAGAIN || errno == EINTR) return 0; @@ -409,8 +414,8 @@ void ul_pty_wait_for_child(struct ul_pty *pty) } } else { /* final wait */ - while ((pid = wait3(&status, options, NULL)) > 0) { - DBG(SIG, ul_debug(" wait3 done [rc=%d]", (int) pid)); + while ((pid = waitpid(-1, &status, options)) > 0) { + DBG(SIG, ul_debug(" waitpid done [rc=%d]", (int) pid)); if (pid == pty->child) { if (pty->callbacks.child_die) pty->callbacks.child_die( @@ -451,9 +456,10 @@ static int handle_signal(struct ul_pty *pty, int fd) else ul_pty_wait_for_child(pty); - } else if (info.ssi_status == SIGSTOP && pty->child > 0) + } 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")); @@ -571,16 +577,15 @@ int ul_pty_proxy_master(struct ul_pty *pty) rc = mainloop_callback(pty); if (rc == 0) continue; - } else + } 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; @@ -594,34 +599,42 @@ int ul_pty_proxy_master(struct ul_pty *pty) 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: + if (i == POLLFD_SIGNAL) rc = handle_signal(pty, pfd[i].fd); + else if (pfd[i].revents & POLLIN) + rc = handle_io(pty, pfd[i].fd, &eof); /* data */ + + if (rc) { + ul_pty_write_eof_to_child(pty); break; } - if (rc) - break; + + if (i == POLLFD_SIGNAL) + continue; + + /* 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")); + } + } } + if (rc) + break; + } + + if (rc && pty->child && pty->child != (pid_t) -1 && !pty->delivered_signal) { + kill(pty->child, SIGTERM); + sleep(2); + kill(pty->child, SIGKILL); } pty_signals_cleanup(pty); @@ -686,9 +699,9 @@ int main(int argc, char *argv[]) shname = shname ? shname + 1 : shell; if (command) - execl(shell, shname, "-c", command, NULL); + execl(shell, shname, "-c", command, (char *)NULL); else - execl(shell, shname, "-i", NULL); + execl(shell, shname, "-i", (char *)NULL); err(EXIT_FAILURE, "failed to execute %s", shell); break; diff --git a/src/utils/lib/pwdutils.c b/src/utils/lib/pwdutils.c index d5f4d2e..d97020c 100644 --- a/src/utils/lib/pwdutils.c +++ b/src/utils/lib/pwdutils.c @@ -1,3 +1,7 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ #include <stdlib.h> #include "c.h" diff --git a/src/utils/lib/randutils.c b/src/utils/lib/randutils.c index bd2a8f6..39edf4e 100644 --- a/src/utils/lib/randutils.c +++ b/src/utils/lib/randutils.c @@ -13,9 +13,9 @@ #include <stdlib.h> #include <string.h> #include <sys/time.h> - +#ifdef __linux__ #include <sys/syscall.h> - +#endif #include "c.h" #include "randutils.h" #include "nls.h" @@ -36,7 +36,7 @@ #endif #if !defined(HAVE_GETRANDOM) && defined(SYS_getrandom) -/* libc without function, but we have syscal */ +/* libc without function, but we have syscall */ #define GRND_NONBLOCK 0x01 #define GRND_RANDOM 0x02 static int getrandom(void *buf, size_t buflen, unsigned int flags) @@ -102,7 +102,12 @@ int random_get_fd(void) #define UL_RAND_READ_ATTEMPTS 8 #define UL_RAND_READ_DELAY 125000 /* microseconds */ -void random_get_bytes(void *buf, size_t nbytes) +/* + * Write @nbytes random bytes into @buf. + * + * Returns 0 for good quality of random bytes or 1 for weak quality. + */ +int ul_random_get_bytes(void *buf, size_t nbytes) { unsigned char *cp = (unsigned char *)buf; size_t i, n = nbytes; @@ -118,7 +123,7 @@ void random_get_bytes(void *buf, size_t nbytes) n -= x; cp += x; lose_counter = 0; - + errno = 0; } else if (errno == ENOSYS) { /* kernel without getrandom() */ break; @@ -177,6 +182,8 @@ void random_get_bytes(void *buf, size_t nbytes) sizeof(ul_jrand_seed)-sizeof(unsigned short)); } #endif + + return n != 0; } @@ -216,7 +223,7 @@ int main(int argc, char *argv[]) printf("Multiple random calls:\n"); for (i = 0; i < n; i++) { - random_get_bytes(&v, sizeof(v)); + ul_random_get_bytes(&v, sizeof(v)); printf("#%02zu: %25"PRIu64"\n", i, v); } @@ -227,7 +234,7 @@ int main(int argc, char *argv[]) if (!buf) err(EXIT_FAILURE, "failed to allocate buffer"); - random_get_bytes(buf, bufsz); + ul_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); diff --git a/src/utils/lib/signames.c b/src/utils/lib/signames.c index 316eec5..064776a 100644 --- a/src/utils/lib/signames.c +++ b/src/utils/lib/signames.c @@ -1,42 +1,11 @@ /* - * 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 <mail@nh2.me> - * - Extracted signal names mapping from kill.c - * - * Copyright (C) 2014 Sami Kerola <kerolasa@iki.fi> - * Copyright (C) 2014 Karel Zak <kzak@redhat.com> - * Copyright (C) 2017 Niklas Hambüchen <mail@nh2.me> + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + + * Written by: + * Sami Kerola <kerolasa@iki.fi> + * Karel Zak <kzak@redhat.com> + * Niklas Hambüchen <mail@nh2.me> */ #include <ctype.h> /* for isdigit() */ diff --git a/src/utils/lib/strutils.c b/src/utils/lib/strutils.c index 304f314..eec4cd5 100644 --- a/src/utils/lib/strutils.c +++ b/src/utils/lib/strutils.c @@ -1114,6 +1114,23 @@ static int test_strutils_cmp_paths(int argc, char *argv[]) return EXIT_SUCCESS; } +static int test_strutils_normalize(int argc, char *argv[]) +{ + unsigned char *str; + size_t sz; + + if (argc < 2) + return EXIT_FAILURE; + + str = (unsigned char *) strdup(argv[1]); + sz = normalize_whitespace(str); + + printf("'%s' --> '%s' [sz=%zu]\n", argv[1], str, sz); + free(str); + + return EXIT_SUCCESS; +} + int main(int argc, char *argv[]) { if (argc == 3 && strcmp(argv[1], "--size") == 0) @@ -1125,10 +1142,17 @@ int main(int argc, char *argv[]) if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0) return test_strdup_to_member(argc - 1, argv + 1); - fprintf(stderr, "usage: %1$s --size <number>[suffix]\n" - " %1$s --cmp-paths <path> <path>\n" - " %1$s --strdup-member <str> <str>\n", - argv[0]); + else if (argc == 3 && strcmp(argv[1], "--normalize") == 0) + return test_strutils_normalize(argc - 1, argv + 1); + + else { + fprintf(stderr, "usage: %1$s --size <number>[suffix]\n" + " %1$s --cmp-paths <path> <path>\n" + " %1$s --strdup-member <str> <str>\n" + " %1$s --normalize <str>\n", + argv[0]); + exit(EXIT_FAILURE); + } return EXIT_FAILURE; } diff --git a/src/utils/lib/sysfs.c b/src/utils/lib/sysfs.c index 5b4de2c..3b75a23 100644 --- a/src/utils/lib/sysfs.c +++ b/src/utils/lib/sysfs.c @@ -874,7 +874,7 @@ int sysfs_devname_is_hidden(const char *prefix, const char *name) 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 */ + char *_name = NULL, *_parent = NULL; /* name as encoded in sysfs */ dev_t dev = 0; int len; @@ -901,21 +901,20 @@ dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char goto done; sysfs_devname_dev_to_sys(_name); + if (parent) { + _parent = strdup(parent); + if (!_parent) + goto done; + } + if (parent && strncmp("dm-", name, 3) != 0) { /* * Create path to /sys/block/<parent>/<name>/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; @@ -934,10 +933,22 @@ dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char goto done; dev = read_devno(buf); + /* + * Read from /sys/block/<parent>/<partition>/dev + */ + if (!dev && parent && startswith(name, parent)) { + len = snprintf(buf, sizeof(buf), + "%s" _PATH_SYS_BLOCK "/%s/%s/dev", + prefix, _parent, _name); + if (len < 0 || (size_t) len >= sizeof(buf)) + goto done; + dev = read_devno(buf); + } + + /* + * Read from /sys/block/<sysname>/device/dev + */ if (!dev) { - /* - * Read from /sys/block/<sysname>/device/dev - */ len = snprintf(buf, sizeof(buf), "%s" _PATH_SYS_BLOCK "/%s/device/dev", prefix, _name); @@ -947,6 +958,7 @@ dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char } done: free(_name); + free(_parent); return dev; } diff --git a/src/utils/lib/timer.c b/src/utils/lib/timer.c index c1ea54e..cfa18f6 100644 --- a/src/utils/lib/timer.c +++ b/src/utils/lib/timer.c @@ -1,4 +1,7 @@ /* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * * Please, don't add this file to libcommon because timers requires * -lrt on systems with old libc (and probably also -lpthread for static * build). diff --git a/src/utils/libsmartcols/CMakeLists.txt b/src/utils/libsmartcols/CMakeLists.txt index 307f06d..7265bea 100644 --- a/src/utils/libsmartcols/CMakeLists.txt +++ b/src/utils/libsmartcols/CMakeLists.txt @@ -8,7 +8,6 @@ add_library(libsmartcols STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/buffer.c ${CMAKE_CURRENT_SOURCE_DIR}/src/calculate.c ${CMAKE_CURRENT_SOURCE_DIR}/src/cell.c ${CMAKE_CURRENT_SOURCE_DIR}/src/column.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/fput.c ${CMAKE_CURRENT_SOURCE_DIR}/src/grouping.c ${CMAKE_CURRENT_SOURCE_DIR}/src/init.c ${CMAKE_CURRENT_SOURCE_DIR}/src/iter.c diff --git a/src/utils/libsmartcols/src/fput.c b/src/utils/libsmartcols/src/fput.c deleted file mode 100644 index b00c3d8..0000000 --- a/src/utils/libsmartcols/src/fput.c +++ /dev/null @@ -1,97 +0,0 @@ -#include "carefulputc.h" -#include "smartcolsP.h" - -void fput_indent(struct libscols_table *tb) -{ - int i; - - for (i = 0; i <= tb->indent; i++) - fputs(" ", tb->out); -} - -void fput_table_open(struct libscols_table *tb) -{ - tb->indent = 0; - - if (scols_table_is_json(tb)) { - fputc('{', tb->out); - fputs(linesep(tb), tb->out); - - fput_indent(tb); - fputs_quoted(tb->name, tb->out); - fputs(": [", tb->out); - fputs(linesep(tb), tb->out); - - tb->indent++; - tb->indent_last_sep = 1; - } -} - -void fput_table_close(struct libscols_table *tb) -{ - tb->indent--; - - if (scols_table_is_json(tb)) { - fput_indent(tb); - fputc(']', tb->out); - tb->indent--; - fputs(linesep(tb), tb->out); - fputc('}', tb->out); - tb->indent_last_sep = 1; - } -} - -void fput_children_open(struct libscols_table *tb) -{ - if (scols_table_is_json(tb)) { - fputc(',', tb->out); - fputs(linesep(tb), tb->out); - fput_indent(tb); - fputs("\"children\": [", tb->out); - } - /* between parent and child is separator */ - fputs(linesep(tb), tb->out); - tb->indent_last_sep = 1; - tb->indent++; - tb->termlines_used++; -} - -void fput_children_close(struct libscols_table *tb) -{ - tb->indent--; - - if (scols_table_is_json(tb)) { - fput_indent(tb); - fputc(']', tb->out); - fputs(linesep(tb), tb->out); - tb->indent_last_sep = 1; - } -} - -void fput_line_open(struct libscols_table *tb) -{ - if (scols_table_is_json(tb)) { - fput_indent(tb); - fputc('{', tb->out); - tb->indent_last_sep = 0; - } - tb->indent++; -} - -void fput_line_close(struct libscols_table *tb, int last, int last_in_table) -{ - tb->indent--; - if (scols_table_is_json(tb)) { - if (tb->indent_last_sep) - fput_indent(tb); - fputs(last ? "}" : "},", tb->out); - if (!tb->no_linesep) - fputs(linesep(tb), tb->out); - - } else if (tb->no_linesep == 0 && last_in_table == 0) { - fputs(linesep(tb), tb->out); - tb->termlines_used++; - } - - tb->indent_last_sep = 1; -} diff --git a/src/utils/libsmartcols/src/libsmartcols.h b/src/utils/libsmartcols/src/libsmartcols.h index 5714bfa..35c24c9 100644 --- a/src/utils/libsmartcols/src/libsmartcols.h +++ b/src/utils/libsmartcols/src/libsmartcols.h @@ -18,6 +18,15 @@ extern "C" { #include <stdio.h> #include <sys/types.h> +#include <xloop/version.h> + +/** + * LIBSMARTCOLS_VERSION: + * + * Library version string + */ +#define LIBSMARTCOLS_VERSION XLOOP_VERSION + /** * libscols_iter: * diff --git a/src/utils/libsmartcols/src/print-api.c b/src/utils/libsmartcols/src/print-api.c index 9a9f2df..89dd3bf 100644 --- a/src/utils/libsmartcols/src/print-api.c +++ b/src/utils/libsmartcols/src/print-api.c @@ -117,8 +117,11 @@ static int do_print_table(struct libscols_table *tb, int *is_empty) if (list_empty(&tb->tb_lines)) { DBG(TAB, ul_debugobj(tb, "ignore -- no lines")); if (scols_table_is_json(tb)) { - fput_table_open(tb); - fput_table_close(tb); + ul_jsonwrt_init(&tb->json, tb->out, 0); + ul_jsonwrt_root_open(&tb->json); + ul_jsonwrt_array_open(&tb->json, tb->name); + ul_jsonwrt_array_close(&tb->json, 1); + ul_jsonwrt_root_close(&tb->json); } else if (is_empty) *is_empty = 1; return 0; @@ -129,7 +132,10 @@ static int do_print_table(struct libscols_table *tb, int *is_empty) if (rc) return rc; - fput_table_open(tb); + if (scols_table_is_json(tb)) { + ul_jsonwrt_root_open(&tb->json); + ul_jsonwrt_array_open(&tb->json, tb->name); + } if (tb->format == SCOLS_FMT_HUMAN) __scols_print_title(tb); @@ -143,7 +149,10 @@ static int do_print_table(struct libscols_table *tb, int *is_empty) else rc = __scols_print_table(tb, buf); - fput_table_close(tb); + if (scols_table_is_json(tb)) { + ul_jsonwrt_array_close(&tb->json, 1); + ul_jsonwrt_root_close(&tb->json); + } done: __scols_cleanup_printing(tb, buf); return rc; @@ -162,7 +171,7 @@ int scols_print_table(struct libscols_table *tb) int empty = 0; int rc = do_print_table(tb, &empty); - if (rc == 0 && !empty) + if (rc == 0 && !empty && !scols_table_is_json(tb)) fputc('\n', tb->out); return rc; } diff --git a/src/utils/libsmartcols/src/print.c b/src/utils/libsmartcols/src/print.c index 1172533..9d78c90 100644 --- a/src/utils/libsmartcols/src/print.c +++ b/src/utils/libsmartcols/src/print.c @@ -444,6 +444,7 @@ static int print_data(struct libscols_table *tb, size_t len = 0, i, width, bytes; const char *color = NULL; char *data, *nextchunk; + const char *name = NULL; int is_last; assert(tb); @@ -453,8 +454,16 @@ static int print_data(struct libscols_table *tb, if (!data) data = ""; + if (tb->format != SCOLS_FMT_HUMAN) + name = scols_cell_get_data(&cl->header); + is_last = is_last_column(cl); + if (is_last && scols_table_is_json(tb) && + scols_table_is_tree(tb) && has_children(ln)) + /* "children": [] is the real last value */ + is_last = 0; + switch (tb->format) { case SCOLS_FMT_RAW: fputs_nonblank(data, tb->out); @@ -463,37 +472,28 @@ static int print_data(struct libscols_table *tb, return 0; case SCOLS_FMT_EXPORT: - fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header)); + fprintf(tb->out, "%s=", name); fputs_quoted(data, tb->out); if (!is_last) fputs(colsep(tb), tb->out); return 0; case SCOLS_FMT_JSON: - fputs_quoted_json_lower(scols_cell_get_data(&cl->header), tb->out); - fputs(":", tb->out); switch (cl->json_type) { - case SCOLS_JSON_STRING: - if (!*data) - fputs("null", tb->out); - else - fputs_quoted_json(data, tb->out); - break; - case SCOLS_JSON_NUMBER: - if (!*data) - fputs("null", tb->out); - else - fputs(data, tb->out); - break; - case SCOLS_JSON_BOOLEAN: - fputs(!*data ? "false" : - *data == '0' ? "false" : - *data == 'N' || *data == 'n' ? "false" : "true", - tb->out); - break; + case SCOLS_JSON_STRING: + ul_jsonwrt_value_s(&tb->json, name, data, is_last); + break; + case SCOLS_JSON_NUMBER: + ul_jsonwrt_value_raw(&tb->json, name, data, is_last); + break; + case SCOLS_JSON_BOOLEAN: + ul_jsonwrt_value_boolean(&tb->json, name, + !*data ? 0 : + *data == '0' ? 0 : + *data == 'N' || *data == 'n' ? 0 : 1, + is_last); + break; } - if (!is_last) - fputs(", ", tb->out); return 0; case SCOLS_FMT_HUMAN: @@ -871,9 +871,17 @@ int __scols_print_range(struct libscols_table *tb, int last = scols_iter_is_last(itr); - fput_line_open(tb); + if (scols_table_is_json(tb)) + ul_jsonwrt_object_open(&tb->json, NULL); + rc = print_line(tb, ln, buf); - fput_line_close(tb, last, last); + + if (scols_table_is_json(tb)) + ul_jsonwrt_object_close(&tb->json, last); + else if (last == 0 && tb->no_linesep == 0) { + fputs(linesep(tb), tb->out); + tb->termlines_used++; + } if (end && ln == end) break; @@ -905,16 +913,22 @@ static int print_tree_line(struct libscols_table *tb, DBG(LINE, ul_debugobj(ln, " printing tree line")); - fput_line_open(tb); + if (scols_table_is_json(tb)) + ul_jsonwrt_object_open(&tb->json, NULL); + rc = print_line(tb, ln, buf); if (rc) return rc; - if (has_children(ln)) - fput_children_open(tb); - - else { - int last_in_tree = scols_walk_is_last(tb, ln); + if (has_children(ln)) { + if (scols_table_is_json(tb)) + ul_jsonwrt_array_open(&tb->json, "children"); + else { + /* between parent and child is separator */ + fputs(linesep(tb), tb->out); + tb->termlines_used++; + } + } else { int last; /* terminate all open last children for JSON */ @@ -923,20 +937,20 @@ static int print_tree_line(struct libscols_table *tb, last = (is_child(ln) && is_last_child(ln)) || (is_tree_root(ln) && is_last_tree_root(tb, ln)); - fput_line_close(tb, last, last_in_tree); + ul_jsonwrt_object_close(&tb->json, last); if (last && is_child(ln)) - fput_children_close(tb); - - last_in_tree = 0; + ul_jsonwrt_array_close(&tb->json, last); ln = ln->parent; } while(ln && last); - } else { - /* standard output */ - last = (is_child(ln) && is_last_child(ln)) || - (is_group_child(ln) && is_last_group_child(ln)); + } else if (tb->no_linesep == 0) { + int last_in_tree = scols_walk_is_last(tb, ln); - fput_line_close(tb, last, last_in_tree); + if (last_in_tree == 0) { + /* standard output */ + fputs(linesep(tb), tb->out); + tb->termlines_used++; + } } } @@ -1029,8 +1043,8 @@ int __scols_initialize_printing(struct libscols_table *tb, struct libscols_buffe extra_bufsz += tb->ncols; /* separator between columns */ break; case SCOLS_FMT_JSON: - if (tb->format == SCOLS_FMT_JSON) - extra_bufsz += tb->nlines * 3; /* indentation */ + ul_jsonwrt_init(&tb->json, tb->out, 0); + extra_bufsz += tb->nlines * 3; /* indentation */ /* fallthrough */ case SCOLS_FMT_EXPORT: { diff --git a/src/utils/libsmartcols/src/smartcolsP.h b/src/utils/libsmartcols/src/smartcolsP.h index e36bb51..5e9b9ec 100644 --- a/src/utils/libsmartcols/src/smartcolsP.h +++ b/src/utils/libsmartcols/src/smartcolsP.h @@ -15,6 +15,7 @@ #include "list.h" #include "strutils.h" #include "color-names.h" +#include "jsonwrt.h" #include "debug.h" #include "libsmartcols.h" @@ -224,8 +225,8 @@ struct libscols_table { struct libscols_symbols *symbols; struct libscols_cell title; /* optional table title (for humans) */ - int indent; /* indentation counter */ - int indent_last_sep;/* last printed has been line separator */ + struct ul_jsonwrt json; /* JSON formatting */ + int format; /* SCOLS_FMT_* */ size_t termlines_used; /* printed line counter */ @@ -357,17 +358,6 @@ int __scols_print_range(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_line *end); -/* - * fput.c - */ -extern void fput_indent(struct libscols_table *tb); -extern void fput_table_open(struct libscols_table *tb); -extern void fput_table_close(struct libscols_table *tb); -extern void fput_children_open(struct libscols_table *tb); -extern void fput_children_close(struct libscols_table *tb); -extern void fput_line_open(struct libscols_table *tb); -extern void fput_line_close(struct libscols_table *tb, int last, int last_in_table); - static inline int is_tree_root(struct libscols_line *ln) { return ln && !ln->parent && !ln->parent_group; |