summaryrefslogtreecommitdiffstats
path: root/src/utils/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/lib')
-rw-r--r--src/utils/lib/canonicalize.c3
-rw-r--r--src/utils/lib/fileutils.c46
-rw-r--r--src/utils/lib/jsonwrt.c148
-rw-r--r--src/utils/lib/loopdev.c91
-rw-r--r--src/utils/lib/path.c31
-rw-r--r--src/utils/lib/pty-session.c13
-rw-r--r--src/utils/lib/pwdutils.c20
-rw-r--r--src/utils/lib/strutils.c242
-rw-r--r--src/utils/lib/sysfs.c11
-rw-r--r--src/utils/lib/timeutils.c11
10 files changed, 412 insertions, 204 deletions
diff --git a/src/utils/lib/canonicalize.c b/src/utils/lib/canonicalize.c
index e101c5b..6f85b47 100644
--- a/src/utils/lib/canonicalize.c
+++ b/src/utils/lib/canonicalize.c
@@ -170,8 +170,7 @@ char *canonicalize_path_restricted(const char *path)
pipes[0] = -1;
errno = 0;
- /* drop permissions */
- if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
+ if (drop_permissions() != 0)
canonical = NULL; /* failed */
else {
char *dmname = NULL;
diff --git a/src/utils/lib/fileutils.c b/src/utils/lib/fileutils.c
index 9da906a..7a8fce2 100644
--- a/src/utils/lib/fileutils.c
+++ b/src/utils/lib/fileutils.c
@@ -110,7 +110,7 @@ unwind:
/*
* portable getdtablesize()
*/
-int get_fd_tabsize(void)
+unsigned int get_fd_tabsize(void)
{
int m;
@@ -129,18 +129,7 @@ int get_fd_tabsize(void)
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)
+void ul_close_all_fds(unsigned int first, unsigned int last)
{
struct dirent *d;
DIR *dir;
@@ -149,25 +138,29 @@ void close_all_fds(const int exclude[], size_t exsz)
if (dir) {
while ((d = xreaddir(dir))) {
char *end;
- int fd;
+ unsigned int fd;
+ int dfd;
errno = 0;
- fd = strtol(d->d_name, &end, 10);
+ fd = strtoul(d->d_name, &end, 10);
if (errno || end == d->d_name || !end || *end)
continue;
- if (dirfd(dir) == fd)
+ dfd = dirfd(dir);
+ if (dfd < 0)
+ continue;
+ if ((unsigned int)dfd == fd)
continue;
- if (in_set(fd, exclude, exsz))
+ if (fd < first || last < fd)
continue;
close(fd);
}
closedir(dir);
} else {
- int fd, tbsz = get_fd_tabsize();
+ unsigned fd, tbsz = get_fd_tabsize();
for (fd = 0; fd < tbsz; fd++) {
- if (!in_set(fd, exclude, exsz))
+ if (first <= fd && fd <= last)
close(fd);
}
}
@@ -181,22 +174,23 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "--mkstemp") == 0) {
FILE *f;
- char *tmpname;
+ char *tmpname = NULL;
+
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));
+# ifdef HAVE_CLOSE_RANGE
+ if (close_range(STDERR_FILENO + 1, ~0U, 0) < 0)
+# endif
+ ul_close_all_fds(STDERR_FILENO + 1, ~0U);
+
} else if (strcmp(argv[1], "--copy-file") == 0) {
int ret = ul_copy_file(STDIN_FILENO, STDOUT_FILENO);
if (ret == UL_COPY_READ_ERROR)
@@ -209,7 +203,7 @@ int main(int argc, char *argv[])
#endif
-int mkdir_p(const char *path, mode_t mode)
+int ul_mkdir_p(const char *path, mode_t mode)
{
char *p, *dir;
int rc = 0;
diff --git a/src/utils/lib/jsonwrt.c b/src/utils/lib/jsonwrt.c
index 00e8b9d..f2003e8 100644
--- a/src/utils/lib/jsonwrt.c
+++ b/src/utils/lib/jsonwrt.c
@@ -8,16 +8,105 @@
*/
#include <stdio.h>
#include <inttypes.h>
+#include <ctype.h>
+#include <cctype.h>
#include "c.h"
-#include "carefulputc.h"
#include "jsonwrt.h"
+/*
+ * Requirements enumerated via testing (V8, Firefox, IE11):
+ *
+ * var charsToEscape = [];
+ * for (var i = 0; i < 65535; i += 1) {
+ * try {
+ * JSON.parse('{"sample": "' + String.fromCodePoint(i) + '"}');
+ * } catch (e) {
+ * charsToEscape.push(i);
+ * }
+ * }
+ */
+static void fputs_quoted_case_json(const char *data, FILE *out, int dir)
+{
+ const char *p;
+
+ fputc('"', out);
+ for (p = data; p && *p; p++) {
+
+ const unsigned int c = (unsigned int) *p;
+
+ /* From http://www.json.org
+ *
+ * The double-quote and backslashes would break out a string or
+ * init an escape sequence if not escaped.
+ *
+ * Note that single-quotes and forward slashes, while they're
+ * in the JSON spec, don't break double-quoted strings.
+ */
+ if (c == '"' || c == '\\') {
+ fputc('\\', out);
+ fputc(c, out);
+ continue;
+ }
+
+ /* All non-control characters OK; do the case swap as required. */
+ if (c >= 0x20) {
+ /*
+ * Don't use locale sensitive ctype.h functions for regular
+ * ASCII chars, because for example with Turkish locale
+ * (aka LANG=tr_TR.UTF-8) toupper('I') returns 'I'.
+ */
+ if (c <= 127)
+ fputc(dir == 1 ? c_toupper(c) :
+ dir == -1 ? c_tolower(c) : *p, out);
+ else
+ fputc(dir == 1 ? toupper(c) :
+ dir == -1 ? tolower(c) : *p, out);
+ continue;
+ }
+
+ /* In addition, all chars under ' ' break Node's/V8/Chrome's, and
+ * Firefox's JSON.parse function
+ */
+ switch (c) {
+ /* Handle short-hand cases to reduce output size. C
+ * has most of the same stuff here, so if there's an
+ * "Escape for C" function somewhere in the STL, we
+ * should probably be using it.
+ */
+ case '\b':
+ fputs("\\b", out);
+ break;
+ case '\t':
+ fputs("\\t", out);
+ break;
+ case '\n':
+ fputs("\\n", out);
+ break;
+ case '\f':
+ fputs("\\f", out);
+ break;
+ case '\r':
+ fputs("\\r", out);
+ break;
+ default:
+ /* Other assorted control characters */
+ fprintf(out, "\\u00%02x", c);
+ break;
+ }
+ }
+ fputc('"', out);
+}
+
+#define fputs_quoted_json(_d, _o) fputs_quoted_case_json(_d, _o, 0)
+#define fputs_quoted_json_upper(_d, _o) fputs_quoted_case_json(_d, _o, 1)
+#define fputs_quoted_json_lower(_d, _o) fputs_quoted_case_json(_d, _o, -1)
void ul_jsonwrt_init(struct ul_jsonwrt *fmt, FILE *out, int indent)
{
fmt->out = out;
fmt->indent = indent;
+ fmt->after_close = 0;
}
void ul_jsonwrt_indent(struct ul_jsonwrt *fmt)
@@ -30,12 +119,16 @@ void ul_jsonwrt_indent(struct ul_jsonwrt *fmt)
void ul_jsonwrt_open(struct ul_jsonwrt *fmt, const char *name, int type)
{
- if (fmt->postponed_break && !name)
- ;
- else {
+ if (name) {
+ if (fmt->after_close)
+ fputs(",\n", fmt->out);
ul_jsonwrt_indent(fmt);
- if (name)
- fputs_quoted_json_lower(name, fmt->out);
+ fputs_quoted_json_lower(name, fmt->out);
+ } else {
+ if (fmt->after_close)
+ fputs(",", fmt->out);
+ else
+ ul_jsonwrt_indent(fmt);
}
switch (type) {
@@ -44,21 +137,22 @@ void ul_jsonwrt_open(struct ul_jsonwrt *fmt, const char *name, int type)
fmt->indent++;
break;
case UL_JSON_ARRAY:
- fputs(name ? ": [\n" : "{\n", fmt->out);
+ fputs(name ? ": [\n" : "[\n", fmt->out);
fmt->indent++;
break;
case UL_JSON_VALUE:
fputs(name ? ": " : " ", fmt->out);
break;
}
- fmt->postponed_break = 0;
+ fmt->after_close = 0;
}
-void ul_jsonwrt_close(struct ul_jsonwrt *fmt, int type, int islast)
+void ul_jsonwrt_close(struct ul_jsonwrt *fmt, int type)
{
- if (fmt->indent == 0) {
- fputs("}\n", fmt->out);
+ if (fmt->indent == 1) {
+ fputs("\n}\n", fmt->out);
fmt->indent--;
+ fmt->after_close = 1;
return;
}
assert(fmt->indent > 0);
@@ -66,63 +160,57 @@ void ul_jsonwrt_close(struct ul_jsonwrt *fmt, int type, int islast)
switch (type) {
case UL_JSON_OBJECT:
fmt->indent--;
+ fputc('\n', fmt->out);
ul_jsonwrt_indent(fmt);
- fputs(islast ? "}" : "},", fmt->out);
+ fputs("}", fmt->out);
break;
case UL_JSON_ARRAY:
fmt->indent--;
+ fputc('\n', fmt->out);
ul_jsonwrt_indent(fmt);
- fputs(islast ? "]" : "],", fmt->out);
+ fputs("]", 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;
- }
+ fmt->after_close = 1;
}
void ul_jsonwrt_value_raw(struct ul_jsonwrt *fmt,
- const char *name, const char *data, int islast)
+ const char *name, const char *data)
{
ul_jsonwrt_value_open(fmt, name);
if (data && *data)
fputs(data, fmt->out);
else
fputs("null", fmt->out);
- ul_jsonwrt_value_close(fmt, islast);
+ ul_jsonwrt_value_close(fmt);
}
void ul_jsonwrt_value_s(struct ul_jsonwrt *fmt,
- const char *name, const char *data, int islast)
+ const char *name, const char *data)
{
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);
+ ul_jsonwrt_value_close(fmt);
}
void ul_jsonwrt_value_u64(struct ul_jsonwrt *fmt,
- const char *name, uint64_t data, int islast)
+ const char *name, uint64_t data)
{
ul_jsonwrt_value_open(fmt, name);
fprintf(fmt->out, "%"PRIu64, data);
- ul_jsonwrt_value_close(fmt, islast);
+ ul_jsonwrt_value_close(fmt);
}
void ul_jsonwrt_value_boolean(struct ul_jsonwrt *fmt,
- const char *name, int data, int islast)
+ const char *name, int data)
{
ul_jsonwrt_value_open(fmt, name);
fputs(data ? "true" : "false", fmt->out);
- ul_jsonwrt_value_close(fmt, islast);
+ ul_jsonwrt_value_close(fmt);
}
-
diff --git a/src/utils/lib/loopdev.c b/src/utils/lib/loopdev.c
index 194daf9..2fb46e2 100644
--- a/src/utils/lib/loopdev.c
+++ b/src/utils/lib/loopdev.c
@@ -41,6 +41,7 @@
#include "canonicalize.h"
#include "blkdev.h"
#include "debug.h"
+#include "fileutils.h"
/*
* Debug stuff (based on include/debug.h)
@@ -542,7 +543,7 @@ static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc)
if (strcmp(d->d_name, ".") == 0
|| strcmp(d->d_name, "..") == 0
- || strncmp(d->d_name, "xloop", 4) != 0)
+ || strncmp(d->d_name, "xloop", 5) != 0)
continue;
snprintf(name, sizeof(name), "%s/xloop/backing_file", d->d_name);
@@ -634,14 +635,30 @@ done:
int is_loopdev(const char *device)
{
struct stat st;
+ int rc = 0;
- if (device && stat(device, &st) == 0 &&
- S_ISBLK(st.st_mode) &&
- major(st.st_rdev) == LOOPDEV_MAJOR)
- return 1;
+ if (!device || stat(device, &st) != 0 || !S_ISBLK(st.st_mode))
+ rc = 0;
+ else if (major(st.st_rdev) == LOOPDEV_MAJOR)
+ rc = 1;
+ else if (sysfs_devno_is_wholedisk(st.st_rdev)) {
+ /* It's possible that kernel creates a device with a different
+ * major number ... check by /sys it's really xloop device.
+ */
+ char name[PATH_MAX], *cn, *p = NULL;
+
+ snprintf(name, sizeof(name), _PATH_SYS_DEVBLOCK "/%d:%d",
+ major(st.st_rdev), minor(st.st_rdev));
+ cn = canonicalize_path(name);
+ if (cn)
+ p = stripoff_last_component(cn);
+ rc = p && startswith(p, "xloop");
+ free(cn);
+ }
- errno = ENODEV;
- return 0;
+ if (rc == 0)
+ errno = ENODEV;
+ return rc;
}
/*
@@ -668,12 +685,12 @@ struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc)
if (ioctl(fd, LOOP_GET_STATUS64, &lc->config.info) == 0) {
lc->has_info = 1;
lc->info_failed = 0;
- DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK"));
+ DBG(CXT, ul_debugobj(lc, "reading xloop_info64 OK"));
return &lc->config.info;
}
lc->info_failed = 1;
- DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED"));
+ DBG(CXT, ul_debugobj(lc, "reading xloop_info64 FAILED"));
return NULL;
}
@@ -1302,7 +1319,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
}
if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) {
- DBG(CXT, ul_debugobj(lc, "failed to determine loopdev size"));
+ DBG(CXT, ul_debugobj(lc, "failed to determine xloopdev size"));
return -errno;
}
@@ -1313,7 +1330,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
}
if (expected_size != size) {
- DBG(CXT, ul_debugobj(lc, "warning: loopdev and expected "
+ DBG(CXT, ul_debugobj(lc, "warning: xloopdev and expected "
"size mismatch (%ju/%ju)",
size, expected_size));
@@ -1329,7 +1346,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
if (expected_size != size) {
errno = ERANGE;
- DBG(CXT, ul_debugobj(lc, "failed to set loopdev size, "
+ DBG(CXT, ul_debugobj(lc, "failed to set xloopdev size, "
"size: %ju, expected: %ju",
size, expected_size));
return -errno;
@@ -1429,8 +1446,8 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
if (ioctl(dev_fd, LOOP_CONFIGURE, &lc->config) < 0) {
rc = -errno;
errsv = errno;
- if (errno != EINVAL) {
- DBG(SETUP, ul_debugobj(lc, "LOOP_CONFIGURE failed: %m"));
+ if (errno != EINVAL && errno != ENOTTY) {
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_CONFIGURE failed: %m"));
goto err;
}
fallback = 1;
@@ -1440,7 +1457,7 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
errsv = -rc;
goto err;
}
- DBG(SETUP, ul_debugobj(lc, "LOOP_CONFIGURE: OK"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_CONFIGURE: OK"));
}
/*
@@ -1451,11 +1468,11 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
rc = -errno;
errsv = errno;
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_FD failed: %m"));
goto err;
}
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_FD: OK"));
if (lc->blocksize > 0
&& (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) {
@@ -1473,11 +1490,11 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
if (err) {
rc = -errno;
errsv = errno;
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_STATUS64 failed: %m"));
goto err;
}
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_STATUS64: OK"));
}
if ((rc = loopcxt_check_size(lc, file_fd)))
@@ -1535,11 +1552,11 @@ int loopcxt_ioctl_status(struct loopdev_cxt *lc)
} while (again);
if (err) {
rc = -errno;
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_STATUS64 failed: %m"));
return rc;
}
- DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK"));
+ DBG(SETUP, ul_debugobj(lc, "XLOOP_SET_STATUS64: OK"));
return 0;
}
@@ -1553,7 +1570,7 @@ int loopcxt_ioctl_capacity(struct loopdev_cxt *lc)
/* 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"));
+ DBG(CXT, ul_debugobj(lc, "XLOOP_SET_CAPACITY failed: %m"));
return rc;
}
@@ -1571,7 +1588,7 @@ int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio)
/* 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"));
+ DBG(CXT, ul_debugobj(lc, "XLOOP_SET_DIRECT_IO failed: %m"));
return rc;
}
@@ -1593,7 +1610,7 @@ int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
/* 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"));
+ DBG(CXT, ul_debugobj(lc, "XLOOP_SET_BLOCK_SIZE failed: %m"));
return rc;
}
@@ -1609,7 +1626,7 @@ int loopcxt_delete_device(struct loopdev_cxt *lc)
return -EINVAL;
if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
- DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m"));
+ DBG(CXT, ul_debugobj(lc, "XLOOP_CLR_FD failed: %m"));
return -errno;
}
@@ -1862,7 +1879,7 @@ int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
/* full match */
if (lc_sizelimit == sizelimit && lc_offset == offset) {
- DBG(CXT, ul_debugobj(lc, "overlapping loop device %s (full match)",
+ DBG(CXT, ul_debugobj(lc, "overlapping xloop device %s (full match)",
loopcxt_get_device(lc)));
rc = 2;
goto found;
@@ -1874,7 +1891,7 @@ int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
if (sizelimit != 0 && offset + sizelimit <= lc_offset)
continue;
- DBG(CXT, ul_debugobj(lc, "overlapping loop device %s",
+ DBG(CXT, ul_debugobj(lc, "overlapping xloop device %s",
loopcxt_get_device(lc)));
rc = 1;
goto found;
@@ -1949,3 +1966,23 @@ int loopdev_count_by_backing_file(const char *filename, char **loopdev)
}
return count;
}
+
+#ifdef TEST_PROGRAM_LOOPDEV
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ goto usage;
+
+ if (strcmp(argv[1], "--is-loopdev") == 0 && argc == 3)
+ printf("%s: %s\n", argv[2], is_loopdev(argv[2]) ? "OK" : "FAIL");
+ else
+ goto usage;
+
+ return EXIT_SUCCESS;
+usage:
+ fprintf(stderr, "usage: %1$s --is-loopdev <dev>\n",
+ program_invocation_short_name);
+ return EXIT_FAILURE;
+}
+#endif
+
diff --git a/src/utils/lib/path.c b/src/utils/lib/path.c
index 75fa853..21f9bd1 100644
--- a/src/utils/lib/path.c
+++ b/src/utils/lib/path.c
@@ -542,22 +542,27 @@ DIR *ul_path_opendirf(struct path_cxt *pc, const char *path, ...)
ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path)
{
int dirfd;
+ ssize_t ssz;
if (!path) {
const char *p = get_absdir(pc);
if (!p)
return -errno;
- return readlink(p, buf, bufsiz);
- }
+ ssz = readlink(p, buf, bufsiz - 1);
+ } else {
+ dirfd = ul_path_get_dirfd(pc);
+ if (dirfd < 0)
+ return dirfd;
- dirfd = ul_path_get_dirfd(pc);
- if (dirfd < 0)
- return dirfd;
+ if (*path == '/')
+ path++;
- if (*path == '/')
- path++;
+ ssz = readlinkat(dirfd, path, buf, bufsiz - 1);
+ }
- return readlinkat(dirfd, path, buf, bufsiz);
+ if (ssz >= 0)
+ buf[ssz] = '\0';
+ return ssz;
}
/*
@@ -617,7 +622,7 @@ int ul_path_readf(struct path_cxt *pc, char *buf, size_t len, const char *path,
* Returns newly allocated buffer with data from file. Maximal size is BUFSIZ
* (send patch if you need something bigger;-)
*
- * Returns size of the string!
+ * Returns size of the string without \0, nothing is allocated if returns <= 0.
*/
int ul_path_read_string(struct path_cxt *pc, char **str, const char *path)
{
@@ -635,6 +640,8 @@ int ul_path_read_string(struct path_cxt *pc, char **str, const char *path)
/* Remove tailing newline (usual in sysfs) */
if (rc > 0 && *(buf + rc - 1) == '\n')
--rc;
+ if (rc == 0)
+ return 0;
buf[rc] = '\0';
*str = strdup(buf);
@@ -1099,7 +1106,7 @@ int main(int argc, char *argv[])
ul_path_init_debug();
- pc = ul_new_path(dir);
+ pc = ul_new_path("%s", dir);
if (!pc)
err(EXIT_FAILURE, "failed to initialize path context");
if (prefix)
@@ -1191,11 +1198,11 @@ int main(int argc, char *argv[])
errx(EXIT_FAILURE, "<file> not defined");
file = argv[optind++];
- if (ul_path_read_string(pc, &res, file) < 0)
+ 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)
+ if (ul_path_readf_string(pc, &res, "%s", file) <= 0)
err(EXIT_FAILURE, "readf string failed");
printf("readf: %s: %s\n", file, res);
diff --git a/src/utils/lib/pty-session.c b/src/utils/lib/pty-session.c
index f4bb004..6f038e1 100644
--- a/src/utils/lib/pty-session.c
+++ b/src/utils/lib/pty-session.c
@@ -18,6 +18,7 @@
#include <paths.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <inttypes.h>
#include "c.h"
#include "all-io.h"
@@ -129,7 +130,8 @@ void ul_pty_set_mainloop_time(struct ul_pty *pty, struct timeval *tv)
} 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));
+ DBG(IO, ul_debugobj(pty, "mainloop time: %"PRId64".%06"PRId64,
+ (int64_t) tv->tv_sec, (int64_t) tv->tv_usec));
}
}
@@ -239,6 +241,15 @@ void ul_pty_cleanup(struct ul_pty *pty)
tcsetattr(STDIN_FILENO, TCSADRAIN, &rtt);
}
+int ul_pty_chownmod_slave(struct ul_pty *pty, uid_t uid, gid_t gid, mode_t mode)
+{
+ if (fchown(pty->slave, uid, gid))
+ return -errno;
+ if (fchmod(pty->slave, mode))
+ return -errno;
+ return 0;
+}
+
/* call me in child process */
void ul_pty_init_slave(struct ul_pty *pty)
{
diff --git a/src/utils/lib/pwdutils.c b/src/utils/lib/pwdutils.c
index d97020c..1c1f13e 100644
--- a/src/utils/lib/pwdutils.c
+++ b/src/utils/lib/pwdutils.c
@@ -3,6 +3,7 @@
* it what you wish.
*/
#include <stdlib.h>
+#include <assert.h>
#include "c.h"
#include "pwdutils.h"
@@ -17,8 +18,8 @@ struct passwd *xgetpwnam(const char *username, char **pwdbuf)
struct passwd *pwd = NULL, *res = NULL;
int rc;
- if (!pwdbuf || !username)
- return NULL;
+ assert(pwdbuf);
+ assert(username);
*pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
pwd = xcalloc(1, sizeof(struct passwd));
@@ -49,8 +50,8 @@ struct group *xgetgrnam(const char *groupname, char **grpbuf)
struct group *grp = NULL, *res = NULL;
int rc;
- if (!grpbuf || !groupname)
- return NULL;
+ assert(grpbuf);
+ assert(groupname);
*grpbuf = xmalloc(UL_GETPW_BUFSIZ);
grp = xcalloc(1, sizeof(struct group));
@@ -77,8 +78,7 @@ struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
struct passwd *pwd = NULL, *res = NULL;
int rc;
- if (!pwdbuf)
- return NULL;
+ assert(pwdbuf);
*pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
pwd = xcalloc(1, sizeof(struct passwd));
@@ -104,11 +104,6 @@ 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
@@ -117,6 +112,9 @@ char *xgetlogin(void)
* environment.
*
* http://austingroupbugs.net/view.php?id=511
+ *
+ * The same implementation is useful for other systems, since getlogin(3)
+ * shouldn't be used as actual identification.
*/
errno = 0;
ruid = getuid();
diff --git a/src/utils/lib/strutils.c b/src/utils/lib/strutils.c
index eec4cd5..096aaf5 100644
--- a/src/utils/lib/strutils.c
+++ b/src/utils/lib/strutils.c
@@ -319,103 +319,125 @@ char *strndup(const char *s, size_t n)
}
#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)
+/*
+ * convert strings to numbers; returns <0 on error, and 0 on success
+ */
+int ul_strtos64(const char *str, int64_t *num, int base)
{
- int32_t num = strtos32_or_err(str, errmesg);
+ char *end = NULL;
- if (num < INT16_MIN || num > INT16_MAX) {
- errno = ERANGE;
- err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
- }
- return num;
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ return -EINVAL;
+ *num = (int64_t) strtoimax(str, &end, base);
+
+ if (errno || str == end || (end && *end))
+ return -EINVAL;
+ return 0;
}
-static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base)
+int ul_strtou64(const char *str, uint64_t *num, int base)
{
- uint32_t num = _strtou32_or_err(str, errmesg, base);
+ char *end = NULL;
+ int64_t tmp;
- if (num > UINT16_MAX) {
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ return -EINVAL;
+
+ /* we need to ignore negative numbers, note that for invalid negative
+ * number strtoimax() returns negative number too, so we do not
+ * need to check errno here */
+ tmp = (int64_t) strtoimax(str, &end, base);
+ if (tmp < 0)
errno = ERANGE;
- err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ else {
+ errno = 0;
+ *num = strtoumax(str, &end, base);
}
- return num;
-}
-uint16_t strtou16_or_err(const char *str, const char *errmesg)
-{
- return _strtou16_or_err(str, errmesg, 10);
+ if (errno || str == end || (end && *end))
+ return -EINVAL;
+ return 0;
}
-uint16_t strtox16_or_err(const char *str, const char *errmesg)
+int ul_strtos32(const char *str, int32_t *num, int base)
{
- return _strtou16_or_err(str, errmesg, 16);
+ int64_t tmp;
+ int rc;
+
+ rc = ul_strtos64(str, &tmp, base);
+ if (rc == 0 && (tmp < INT32_MIN || tmp > INT32_MAX))
+ rc = -(errno = ERANGE);
+ if (rc == 0)
+ *num = (int32_t) tmp;
+ return rc;
}
-int32_t strtos32_or_err(const char *str, const char *errmesg)
+int ul_strtou32(const char *str, uint32_t *num, int base)
{
- 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;
+ uint64_t tmp;
+ int rc;
+
+ rc = ul_strtou64(str, &tmp, base);
+ if (rc == 0 && tmp > UINT32_MAX)
+ rc = -(errno = ERANGE);
+ if (rc == 0)
+ *num = (uint32_t) tmp;
+ return rc;
}
-static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base)
+/*
+ * Covert strings to numbers in defined range and print message on error.
+ *
+ * These functions are used when we read input from users (getopt() etc.). It's
+ * better to consolidate the code and keep it all based on 64-bit numbers then
+ * implement it for 32 and 16-bit numbers too.
+ */
+int64_t str2num_or_err(const char *str, int base, const char *errmesg,
+ int64_t low, int64_t up)
{
- uint64_t num = _strtou64_or_err(str, errmesg, base);
+ int64_t num = 0;
+ int rc;
- if (num > UINT32_MAX) {
- errno = ERANGE;
- err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ rc = ul_strtos64(str, &num, base);
+ if (rc == 0 && ((low && num < low) || (up && num > up)))
+ rc = -(errno = ERANGE);
+
+ if (rc) {
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ errx(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)
+uint64_t str2unum_or_err(const char *str, int base, const char *errmesg, uint64_t up)
{
- int64_t num;
- char *end = NULL;
-
- errno = 0;
- if (str == NULL || *str == '\0')
- goto err;
- num = strtoimax(str, &end, 10);
+ uint64_t num = 0;
+ int rc;
- if (errno || str == end || (end && *end))
- goto err;
+ rc = ul_strtou64(str, &num, base);
+ if (rc == 0 && (up && num > up))
+ rc = -(errno = ERANGE);
+ if (rc) {
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
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)
+double strtod_or_err(const char *str, const char *errmesg)
{
- uintmax_t num;
+ double num;
char *end = NULL;
errno = 0;
if (str == NULL || *str == '\0')
goto err;
- num = strtoumax(str, &end, base);
+ num = strtod(str, &end);
if (errno || str == end || (end && *end))
goto err;
@@ -428,17 +450,7 @@ err:
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)
+long double strtold_or_err(const char *str, const char *errmesg)
{
double num;
char *end = NULL;
@@ -446,7 +458,7 @@ double strtod_or_err(const char *str, const char *errmesg)
errno = 0;
if (str == NULL || *str == '\0')
goto err;
- num = strtod(str, &end);
+ num = strtold(str, &end);
if (errno || str == end || (end && *end))
goto err;
@@ -517,11 +529,19 @@ uintmax_t strtosize_or_err(const char *str, const char *errmesg)
void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
{
- double user_input;
+ long double user_input;
- user_input = strtod_or_err(str, errmesg);
+ user_input = strtold_or_err(str, errmesg);
tv->tv_sec = (time_t) user_input;
- tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
+ tv->tv_usec = (suseconds_t)((user_input - tv->tv_sec) * 1000000);
+}
+
+time_t strtotime_or_err(const char *str, const char *errmesg)
+{
+ int64_t user_input;
+
+ user_input = strtos64_or_err(str, errmesg);
+ return (time_t) user_input;
}
/*
@@ -1045,6 +1065,36 @@ int skip_fline(FILE *fp)
} while (1);
}
+
+/* compare two strings, but ignoring non-alnum and case of the characters, for example
+ * "Hello (123)!" is the same as "hello123".
+ */
+int ul_stralnumcmp(const char *p1, const char *p2)
+{
+ const unsigned char *s1 = (const unsigned char *) p1;
+ const unsigned char *s2 = (const unsigned char *) p2;
+ unsigned char c1, c2;
+
+ do {
+ do {
+ c1 = (unsigned char) *s1++;
+ } while (c1 != '\0' && !isalnum((unsigned int) c1));
+
+ do {
+ c2 = (unsigned char) *s2++;
+ } while (c2 != '\0' && !isalnum((unsigned int) c2));
+
+ if (c1 != '\0')
+ c1 = tolower(c1);
+ if (c2 != '\0')
+ c2 = tolower(c2);
+ if (c1 == '\0')
+ return c1 - c2;
+ } while (c1 == c2);
+
+ return c1 - c2;
+}
+
#ifdef TEST_PROGRAM_STRUTILS
struct testS {
char *name;
@@ -1133,23 +1183,49 @@ static int test_strutils_normalize(int argc, char *argv[])
int main(int argc, char *argv[])
{
- if (argc == 3 && strcmp(argv[1], "--size") == 0)
+ 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)
+ } else 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)
+ } else if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0) {
return test_strdup_to_member(argc - 1, argv + 1);
- else if (argc == 3 && strcmp(argv[1], "--normalize") == 0)
+ } else if (argc == 4 && strcmp(argv[1], "--stralnumcmp") == 0) {
+ printf("%s\n", ul_stralnumcmp(argv[2], argv[3]) == 0 ?
+ "match" : "dismatch");
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--normalize") == 0) {
return test_strutils_normalize(argc - 1, argv + 1);
- else {
+
+ } else if (argc == 3 && strcmp(argv[1], "--strtos64") == 0) {
+ printf("'%s'-->%jd\n", argv[2], strtos64_or_err(argv[2], "strtos64 failed"));
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--strtou64") == 0) {
+ printf("'%s'-->%ju\n", argv[2], strtou64_or_err(argv[2], "strtou64 failed"));
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--strtos32") == 0) {
+ printf("'%s'-->%d\n", argv[2], strtos32_or_err(argv[2], "strtos32 failed"));
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--strtou32") == 0) {
+ printf("'%s'-->%u\n", argv[2], strtou32_or_err(argv[2], "strtou32 failed"));
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--strtos16") == 0) {
+ printf("'%s'-->%hd\n", argv[2], strtos16_or_err(argv[2], "strtos16 failed"));
+ return EXIT_SUCCESS;
+ } else if (argc == 3 && strcmp(argv[1], "--strtou16") == 0) {
+ printf("'%s'-->%hu\n", argv[2], strtou16_or_err(argv[2], "strtou16 failed"));
+ return EXIT_SUCCESS;
+
+ } 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",
+ " %1$s --stralnumcmp <str> <str>\n"
+ " %1$s --normalize <str>\n"
+ " %1$s --strto{s,u}{16,32,64} <str>\n",
argv[0]);
exit(EXIT_FAILURE);
}
diff --git a/src/utils/lib/sysfs.c b/src/utils/lib/sysfs.c
index 3b75a23..bb71833 100644
--- a/src/utils/lib/sysfs.c
+++ b/src/utils/lib/sysfs.c
@@ -182,10 +182,9 @@ char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz)
ssize_t sz;
/* read /sys/dev/block/<maj:min> link */
- sz = ul_path_readlink(pc, link, sizeof(link) - 1, NULL);
+ sz = ul_path_readlink(pc, link, sizeof(link), NULL);
if (sz < 0)
return NULL;
- link[sz] = '\0';
name = strrchr(link, '/');
if (!name)
@@ -393,7 +392,7 @@ char *sysfs_blkdev_get_devchain(struct path_cxt *pc, char *buf, size_t bufsz)
if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz)
return NULL;
- buf[sz++] = '\0';
+ sz++;
prefix = ul_path_get_prefix(pc);
if (prefix)
psz = strlen(prefix);
@@ -567,10 +566,9 @@ int sysfs_blkdev_get_wholedisk( struct path_cxt *pc,
char *name;
ssize_t linklen;
- linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath) - 1, NULL);
+ linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath), NULL);
if (linklen < 0)
goto err;
- linkpath[linklen] = '\0';
stripoff_last_component(linkpath); /* dirname */
name = stripoff_last_component(linkpath); /* basename */
@@ -678,11 +676,10 @@ int sysfs_blkdev_scsi_get_hctl(struct path_cxt *pc, int *h, int *c, int *t, int
goto done;
blk->hctl_error = 1;
- len = ul_path_readlink(pc, buf, sizeof(buf) - 1, "device");
+ len = ul_path_readlink(pc, buf, sizeof(buf), "device");
if (len < 0)
return len;
- buf[len] = '\0';
hctl = strrchr(buf, '/');
if (!hctl)
return -1;
diff --git a/src/utils/lib/timeutils.c b/src/utils/lib/timeutils.c
index 8b443cd..2e28ada 100644
--- a/src/utils/lib/timeutils.c
+++ b/src/utils/lib/timeutils.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
+#include <inttypes.h>
#include "c.h"
#include "nls.h"
@@ -438,14 +439,14 @@ static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf
}
if (flags & ISO_DOTUSEC) {
- len = snprintf(p, bufsz, ".%06ld", (long) usec);
+ len = snprintf(p, bufsz, ".%06"PRId64, (int64_t) 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);
+ len = snprintf(p, bufsz, ",%06"PRId64, (int64_t) usec);
if (len < 0 || (size_t) len > bufsz)
goto err;
bufsz -= len;
@@ -480,7 +481,7 @@ int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz)
if (rc)
return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz);
- warnx(_("time %ld is out of range."), tv->tv_sec);
+ warnx(_("time %"PRId64" is out of range."), (int64_t)(tv->tv_sec));
return -1;
}
@@ -504,7 +505,7 @@ int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz)
if (rc)
return format_iso_time(&tm, 0, flags, buf, bufsz);
- warnx(_("time %ld is out of range."), (long)t);
+ warnx(_("time %"PRId64" is out of range."), (int64_t)*t);
return -1;
}
@@ -581,7 +582,7 @@ int main(int argc, char *argv[])
}
if (strcmp(argv[1], "--timestamp") == 0) {
- usec_t usec;
+ usec_t usec = 0;
parse_timestamp(argv[2], &usec);
tv.tv_sec = (time_t) (usec / 1000000);