X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=util.c;h=f7d538aaacf87496367661ba3822bc2f44cb6070;hp=17ee09c1f7d23da9782c3db0b4432f505c7579d0;hb=8407a5d0183d9513349754f1eac86e2fdec8bd76;hpb=aaf694ca54365997a1ba103832db12605da9023f diff --git a/util.c b/util.c index 17ee09c1f..f7d538aaa 100644 --- a/util.c +++ b/util.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -113,6 +115,9 @@ bool endswith(const char *s, const char *postfix) { sl = strlen(s); pl = strlen(postfix); + if (pl == 0) + return true; + if (sl < pl) return false; @@ -128,12 +133,39 @@ bool startswith(const char *s, const char *prefix) { sl = strlen(s); pl = strlen(prefix); + if (pl == 0) + return true; + if (sl < pl) return false; return memcmp(s, prefix, pl) == 0; } +bool startswith_no_case(const char *s, const char *prefix) { + size_t sl, pl; + unsigned i; + + assert(s); + assert(prefix); + + sl = strlen(s); + pl = strlen(prefix); + + if (pl == 0) + return true; + + if (sl < pl) + return false; + + for(i = 0; i < pl; ++i) { + if (tolower(s[i]) != tolower(prefix[i])) + return false; + } + + return true; +} + bool first_word(const char *s, const char *word) { size_t sl, wl; @@ -146,11 +178,14 @@ bool first_word(const char *s, const char *word) { if (sl < wl) return false; + if (wl == 0) + return true; + if (memcmp(s, word, wl) != 0) return false; - return (s[wl] == 0 || - strchr(WHITESPACE, s[wl])); + return s[wl] == 0 || + strchr(WHITESPACE, s[wl]); } int close_nointr(int fd) { @@ -1041,16 +1076,15 @@ char *bus_path_escape(const char *s) { return r; } -char *bus_path_unescape(const char *s) { +char *bus_path_unescape(const char *f) { char *r, *t; - const char *f; - assert(s); + assert(f); - if (!(r = new(char, strlen(s)+1))) + if (!(r = strdup(f))) return NULL; - for (f = s, t = r; *f; f++) { + for (t = r; *f; f++) { if (*f == '_') { int a, b; @@ -1140,6 +1174,39 @@ bool path_startswith(const char *path, const char *prefix) { } } +bool path_equal(const char *a, const char *b) { + assert(a); + assert(b); + + if ((a[0] == '/') != (b[0] == '/')) + return false; + + for (;;) { + size_t j, k; + + a += strspn(a, "/"); + b += strspn(b, "/"); + + if (*a == 0 && *b == 0) + return true; + + if (*a == 0 || *b == 0) + return false; + + j = strcspn(a, "/"); + k = strcspn(b, "/"); + + if (j != k) + return false; + + if (memcmp(a, b, j) != 0) + return false; + + a += j; + b += k; + } +} + char *ascii_strlower(char *t) { char *p; @@ -1157,6 +1224,7 @@ bool ignore_file(const char *filename) { return filename[0] == '.' || + streq(filename, "lost+found") || endswith(filename, "~") || endswith(filename, ".rpmnew") || endswith(filename, ".rpmsave") || @@ -1215,7 +1283,7 @@ int close_all_fds(const int except[], unsigned n_except) { while ((de = readdir(d))) { int fd = -1; - if (de->d_name[0] == '.') + if (ignore_file(de->d_name)) continue; if ((r = safe_atoi(de->d_name, &fd)) < 0) @@ -1291,7 +1359,9 @@ bool fstype_is_network(const char *fstype) { "smbfs", "ncpfs", "nfs", - "nfs4" + "nfs4", + "gfs", + "gfs2" }; unsigned i; @@ -1324,7 +1394,7 @@ int chvt(int vt) { if (ioctl(fd, VT_ACTIVATE, vt) < 0) r = -errno; - close_nointr(r); + close_nointr_nofail(r); return r; } @@ -1387,10 +1457,14 @@ int ask(char *ret, const char *replies, const char *text, ...) { int r; bool need_nl = true; + fputs("\x1B[1m", stdout); + va_start(ap, text); vprintf(text, ap); va_end(ap); + fputs("\x1B[0m", stdout); + fflush(stdout); if ((r = read_one_char(stdin, &c, &need_nl)) < 0) { @@ -1525,7 +1599,7 @@ int flush_fd(int fd) { } int acquire_terminal(const char *name, bool fail, bool force) { - int fd = -1, notify = -1, r, wd; + int fd = -1, notify = -1, r, wd = -1; assert(name); @@ -1555,8 +1629,9 @@ int acquire_terminal(const char *name, bool fail, bool force) { } for (;;) { - if ((r = flush_fd(notify)) < 0) - goto fail; + if (notify >= 0) + if ((r = flush_fd(notify)) < 0) + goto fail; /* We pass here O_NOCTTY only so that we can check the return * value TIOCSCTTY and have a reliable way to figure out if we @@ -1612,7 +1687,7 @@ int acquire_terminal(const char *name, bool fail, bool force) { } if (notify >= 0) - close_nointr(notify); + close_nointr_nofail(notify); if ((r = reset_terminal(fd)) < 0) log_warning("Failed to reset terminal: %s", strerror(-r)); @@ -1621,23 +1696,34 @@ int acquire_terminal(const char *name, bool fail, bool force) { fail: if (fd >= 0) - close_nointr(fd); + close_nointr_nofail(fd); if (notify >= 0) - close_nointr(notify); + close_nointr_nofail(notify); return r; } int release_terminal(void) { int r = 0, fd; + struct sigaction sa_old, sa_new; - if ((fd = open("/dev/tty", O_RDWR)) < 0) + if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0) return -errno; + /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed + * by our own TIOCNOTTY */ + + zero(sa_new); + sa_new.sa_handler = SIG_IGN; + sa_new.sa_flags = SA_RESTART; + assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); + if (ioctl(fd, TIOCNOTTY) < 0) r = -errno; + assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); + close_nointr_nofail(fd); return r; } @@ -1652,6 +1738,205 @@ int ignore_signal(int sig) { return sigaction(sig, &sa, NULL); } +int close_pipe(int p[]) { + int a = 0, b = 0; + + assert(p); + + if (p[0] >= 0) { + a = close_nointr(p[0]); + p[0] = -1; + } + + if (p[1] >= 0) { + b = close_nointr(p[1]); + p[1] = -1; + } + + return a < 0 ? a : b; +} + +ssize_t loop_read(int fd, void *buf, size_t nbytes) { + uint8_t *p; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + p = buf; + + while (nbytes > 0) { + ssize_t k; + + if ((k = read(fd, p, nbytes)) <= 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) { + struct pollfd pollfd; + + zero(pollfd); + pollfd.fd = fd; + pollfd.events = POLLIN; + + if (poll(&pollfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + + return n > 0 ? n : -errno; + } + + if (pollfd.revents != POLLIN) + return n > 0 ? n : -EIO; + + continue; + } + + return n > 0 ? n : (k < 0 ? -errno : 0); + } + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + +int path_is_mount_point(const char *t) { + struct stat a, b; + char *copy; + + if (lstat(t, &a) < 0) { + + if (errno == ENOENT) + return 0; + + return -errno; + } + + if (!(copy = strdup(t))) + return -ENOMEM; + + if (lstat(dirname(copy), &b) < 0) { + free(copy); + return -errno; + } + + free(copy); + + return a.st_dev != b.st_dev; +} + +int parse_usec(const char *t, usec_t *usec) { + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "sec", USEC_PER_SEC }, + { "s", USEC_PER_SEC }, + { "min", USEC_PER_MINUTE }, + { "hr", USEC_PER_HOUR }, + { "h", USEC_PER_HOUR }, + { "d", USEC_PER_DAY }, + { "w", USEC_PER_WEEK }, + { "msec", USEC_PER_MSEC }, + { "ms", USEC_PER_MSEC }, + { "m", USEC_PER_MINUTE }, + { "usec", 1ULL }, + { "us", 1ULL }, + { "", USEC_PER_SEC }, + }; + + const char *p; + usec_t r = 0; + + assert(t); + assert(usec); + + p = t; + do { + long long l; + char *e; + unsigned i; + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno != 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + r += (usec_t) l * table[i].usec; + p = e + strlen(table[i].suffix); + break; + } + + if (i >= ELEMENTSOF(table)) + return -EINVAL; + + } while (*p != 0); + + *usec = r; + + return 0; +} + +int make_stdio(int fd) { + int r, s, t; + + assert(fd >= 0); + + r = dup2(fd, STDIN_FILENO); + s = dup2(fd, STDOUT_FILENO); + t = dup2(fd, STDERR_FILENO); + + if (fd >= 3) + close_nointr_nofail(fd); + + if (r < 0 || s < 0 || t < 0) + return -errno; + + return 0; +} + +bool is_clean_exit(int code, int status) { + + if (code == CLD_EXITED) + return status == 0; + + /* If a daemon does not implement handlers for some of the + * signals that's not considered an unclean shutdown */ + if (code == CLD_KILLED) + return + status == SIGHUP || + status == SIGINT || + status == SIGTERM || + status == SIGPIPE; + + return false; +} + +bool is_device_path(const char *path) { + + /* Returns true on paths that refer to a device, either in + * sysfs or in /dev */ + + return + path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",