assert(fn);
assert(line);
- if (!(f = fopen(fn, "we")))
+ f = fopen(fn, "we");
+ if (!f)
return -errno;
errno = 0;
assert_se(uname(&u) >= 0);
- if (u.nodename[0])
+ if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
return strdup(u.nodename);
return strdup(u.sysname);
}
+bool hostname_is_set(void) {
+ struct utsname u;
+
+ assert_se(uname(&u) >= 0);
+
+ return !isempty(u.nodename) && !streq(u.nodename, "(none)");
+}
+
char* getlogname_malloc(void) {
uid_t uid;
long bufsize;
return 0;
}
-static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
+int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
DIR *d;
int ret = 0;
assert(fd >= 0);
/* This returns the first error we run into, but nevertheless
- * tries to go on */
+ * tries to go on. This closes the passed fd. */
- if (!(d = fdopendir(fd))) {
+ d = fdopendir(fd);
+ if (!d) {
close_nointr_nofail(fd);
return errno == ENOENT ? 0 : -errno;
for (;;) {
struct dirent buf, *de;
- bool is_dir, keep_around = false;
+ bool is_dir, keep_around;
+ struct stat st;
int r;
- if ((r = readdir_r(d, &buf, &de)) != 0) {
- if (ret == 0)
- ret = -r;
+ r = readdir_r(d, &buf, &de);
+ if (r != 0 && ret == 0) {
+ ret = -r;
break;
}
if (streq(de->d_name, ".") || streq(de->d_name, ".."))
continue;
- if (de->d_type == DT_UNKNOWN) {
- struct stat st;
-
+ if (de->d_type == DT_UNKNOWN ||
+ honour_sticky ||
+ (de->d_type == DT_DIR && root_dev)) {
if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
if (ret == 0 && errno != ENOENT)
ret = -errno;
continue;
}
- if (honour_sticky)
- keep_around =
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
-
is_dir = S_ISDIR(st.st_mode);
-
+ keep_around =
+ honour_sticky &&
+ (st.st_uid == 0 || st.st_uid == getuid()) &&
+ (st.st_mode & S_ISVTX);
} else {
- if (honour_sticky) {
- struct stat st;
-
- if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
-
- keep_around =
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
- }
-
is_dir = de->d_type == DT_DIR;
+ keep_around = false;
}
if (is_dir) {
int subdir_fd;
- subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+ /* if root_dev is set, remove subdirectories only, if device is same as dir */
+ if (root_dev && st.st_dev != root_dev->st_dev)
+ continue;
+
+ subdir_fd = openat(fd, de->d_name,
+ O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (subdir_fd < 0) {
if (ret == 0 && errno != ENOENT)
ret = -errno;
continue;
}
- if ((r = rm_rf_children(subdir_fd, only_dirs, honour_sticky)) < 0) {
- if (ret == 0)
- ret = r;
- }
+ r = rm_rf_children(subdir_fd, only_dirs, honour_sticky, root_dev);
+ if (r < 0 && ret == 0)
+ ret = r;
if (!keep_around)
if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
assert(path);
- if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (fd < 0) {
if (errno != ENOTDIR)
return -errno;
if (delete_root && !only_dirs)
- if (unlink(path) < 0)
+ if (unlink(path) < 0 && errno != ENOENT)
return -errno;
return 0;
}
- r = rm_rf_children(fd, only_dirs, honour_sticky);
+ r = rm_rf_children(fd, only_dirs, honour_sticky, NULL);
if (delete_root) {
}
void status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
- char *s = NULL, *spaces = NULL, *e;
- int fd = -1, c;
- size_t emax, sl, left;
+ char *s = NULL;
+ static const char status_indent[] = " "; /* "[" STATUS "] " */
+ int fd = -1;
struct iovec iovec[5];
int n = 0;
assert(format);
- /* This independent of logging, as status messages are
+ /* This is independent of logging, as status messages are
* optional and go exclusively to the console. */
if (vasprintf(&s, format, ap) < 0)
goto finish;
if (ellipse) {
+ char *e;
+ size_t emax, sl;
+ int c;
+
c = fd_columns(fd);
if (c <= 0)
c = 80;
- if (status) {
- sl = 2 + 6 + 1; /* " [" status "]" */
- emax = (size_t) c > sl ? c - sl - 1 : 0;
- } else
- emax = c - 1;
+ sl = status ? strlen(status_indent) : 0;
+
+ emax = c - sl - 1;
+ if (emax < 3)
+ emax = 3;
e = ellipsize(s, emax, 75);
if (e) {
}
zero(iovec);
- IOVEC_SET_STRING(iovec[n++], s);
- if (ellipse) {
- sl = strlen(s);
- left = emax > sl ? emax - sl : 0;
- if (left > 0) {
- spaces = malloc(left);
- if (spaces) {
- memset(spaces, ' ', left);
- iovec[n].iov_base = spaces;
- iovec[n].iov_len = left;
- n++;
- }
- }
+ if (status) {
+ if (!isempty(status)) {
+ IOVEC_SET_STRING(iovec[n++], "[");
+ IOVEC_SET_STRING(iovec[n++], status);
+ IOVEC_SET_STRING(iovec[n++], "] ");
+ } else
+ IOVEC_SET_STRING(iovec[n++], status_indent);
}
- if (status) {
- IOVEC_SET_STRING(iovec[n++], " [");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "]\n");
- } else
- IOVEC_SET_STRING(iovec[n++], "\n");
+ IOVEC_SET_STRING(iovec[n++], s);
+ IOVEC_SET_STRING(iovec[n++], "\n");
writev(fd, iovec, n);
finish:
free(s);
- free(spaces);
if (fd >= 0)
close_nointr_nofail(fd);
return r;
}
+
+int can_sleep(const char *type) {
+ char *p, *w, *state;
+ size_t l, k;
+ bool found = false;
+ int r;
+
+ assert(type);
+
+ r = read_one_line_file("/sys/power/state", &p);
+ if (r < 0)
+ return r == -ENOENT ? 0 : r;
+
+ k = strlen(type);
+
+ FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
+ if (l == k && strncmp(w, type, l) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ free(p);
+ return found;
+}
+
+bool is_valid_documentation_url(const char *url) {
+ assert(url);
+
+ if (startswith(url, "http://") && url[7])
+ return true;
+
+ if (startswith(url, "https://") && url[8])
+ return true;
+
+ if (startswith(url, "file:") && url[5])
+ return true;
+
+ if (startswith(url, "info:") && url[5])
+ return true;
+
+ if (startswith(url, "man:") && url[4])
+ return true;
+
+ return false;
+}
+
+bool in_initrd(void) {
+ static int saved = -1;
+
+ if (saved < 0)
+ saved = access("/etc/initrd-release", F_OK) >= 0;
+
+ return saved;
+}
+
+void warn_melody(void) {
+ int fd;
+
+ fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return;
+
+ /* Yeah, this is synchronous. Kinda sucks. Bute well... */
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/440));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/220));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/220));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, 0);
+ close_nointr_nofail(fd);
+}