#include <linux/rtc.h>
#include <glob.h>
#include <grp.h>
+#include <sys/mman.h>
#include "macro.h"
#include "util.h"
static __thread size_t pgsz = 0;
long r;
- if (_likely_(pgsz))
+ if (_likely_(pgsz > 0))
return pgsz;
assert_se((r = sysconf(_SC_PAGESIZE)) > 0);
return s;
}
-int get_process_name(pid_t pid, char **name) {
- char *p;
+int get_process_comm(pid_t pid, char **name) {
int r;
- assert(pid >= 1);
assert(name);
- if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0)
- return -ENOMEM;
-
- r = read_one_line_file(p, name);
- free(p);
+ if (pid == 0)
+ r = read_one_line_file("/proc/self/comm", name);
+ else {
+ char *p;
+ if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0)
+ return -ENOMEM;
- if (r < 0)
- return r;
+ r = read_one_line_file(p, name);
+ free(p);
+ }
- return 0;
+ return r;
}
-int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
- char *p, *r, *k;
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
+ char *r, *k;
int c;
bool space = false;
size_t left;
FILE *f;
- assert(pid >= 1);
assert(max_length > 0);
assert(line);
- if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
- return -ENOMEM;
+ if (pid == 0)
+ f = fopen("/proc/self/cmdline", "re");
+ else {
+ char *p;
+ if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
+ return -ENOMEM;
- f = fopen(p, "re");
- free(p);
+ f = fopen(p, "re");
+ free(p);
+ }
if (!f)
return -errno;
- if (!(r = new(char, max_length))) {
+ r = new(char, max_length);
+ if (!r) {
fclose(f);
return -ENOMEM;
}
free(r);
- if ((h = get_process_name(pid, &t)) < 0)
+ if (!comm_fallback)
+ return -ENOENT;
+
+ h = get_process_comm(pid, &t);
+ if (h < 0)
return h;
- h = asprintf(&r, "[%s]", t);
+ r = join("[", t, "]", NULL);
free(t);
- if (h < 0)
+ if (!r)
return -ENOMEM;
}
return 0;
}
+int get_process_exe(pid_t pid, char **name) {
+ int r;
+
+ assert(name);
+
+ if (pid == 0)
+ r = readlink_malloc("/proc/self/exe", name);
+ else {
+ char *p;
+ if (asprintf(&p, "/proc/%lu/exe", (unsigned long) pid) < 0)
+ return -ENOMEM;
+
+ r = readlink_malloc(p, name);
+ free(p);
+ }
+
+ return r;
+}
+
+int get_process_uid(pid_t pid, uid_t *uid) {
+ char *p;
+ FILE *f;
+ int r;
+
+ assert(uid);
+
+ if (pid == 0)
+ return getuid();
+
+ if (asprintf(&p, "/proc/%lu/status", (unsigned long) pid) < 0)
+ return -ENOMEM;
+
+ f = fopen(p, "re");
+ free(p);
+
+ if (!f)
+ return -errno;
+
+ while (!feof(f)) {
+ char line[LINE_MAX], *l;
+
+ if (!fgets(line, sizeof(line), f)) {
+ if (feof(f))
+ break;
+
+ r = -errno;
+ goto finish;
+ }
+
+ l = strstrip(line);
+
+ if (startswith(l, "Uid:")) {
+ l += 4;
+ l += strspn(l, WHITESPACE);
+
+ l[strcspn(l, WHITESPACE)] = 0;
+
+ r = parse_uid(l, uid);
+ goto finish;
+ }
+ }
+
+ r = -EIO;
+
+finish:
+ fclose(f);
+
+ return r;
+}
+
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
bool need_nl = true;
if (on_tty)
- fputs("\x1B[1m", stdout);
+ fputs(ANSI_HIGHLIGHT_ON, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
if (on_tty)
- fputs("\x1B[0m", stdout);
+ fputs(ANSI_HIGHLIGHT_OFF, stdout);
fflush(stdout);
int reset_terminal_fd(int fd) {
struct termios termios;
int r = 0;
- long arg;
/* Set terminal to some sane defaults */
/* Disable exclusive mode, just in case */
ioctl(fd, TIOCNXCL);
+ /* Switch to text mode */
+ ioctl(fd, KDSETMODE, KD_TEXT);
+
/* Enable console unicode mode */
- arg = K_UNICODE;
- ioctl(fd, KDSKBMODE, &arg);
+ ioctl(fd, KDSKBMODE, K_UNICODE);
if (tcgetattr(fd, &termios) < 0) {
r = -errno;
ssize_t l;
struct inotify_event *e;
- if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
+ if ((l = read(notify, inotify_buffer, sizeof(inotify_buffer))) < 0) {
if (errno == EINTR)
continue;
while (nbytes > 0) {
ssize_t k;
- if ((k = write(fd, p, nbytes)) <= 0) {
+ k = write(fd, p, nbytes);
+ if (k <= 0) {
if (k < 0 && errno == EINTR)
continue;
{ "M", 1024ULL*1024ULL },
{ "G", 1024ULL*1024ULL*1024ULL },
{ "T", 1024ULL*1024ULL*1024ULL*1024ULL },
+ { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+ { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
{ "", 1 },
};
return 0;
}
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+ assert(fd >= 0);
+
+ /* Under the assumption that we are running privileged we
+ * first change the access mode and only then hand out
+ * ownership to avoid a window where access is too open. */
+
+ if (fchmod(fd, mode) < 0)
+ return -errno;
+
+ if (fchown(fd, uid, gid) < 0)
+ return -errno;
+
+ return 0;
+}
+
cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
cpu_set_t *r;
unsigned n = 1024;
}
}
-void status_vprintf(const char *format, va_list ap) {
- char *s = NULL;
- int fd = -1;
+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;
+ struct iovec iovec[5];
+ int n = 0;
assert(format);
if (vasprintf(&s, format, ap) < 0)
goto finish;
- if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
+ fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
goto finish;
- write(fd, s, strlen(s));
+ if (ellipse) {
+ 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;
+
+ e = ellipsize(s, emax, 75);
+ if (e) {
+ free(s);
+ s = 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) {
+ IOVEC_SET_STRING(iovec[n++], " [");
+ IOVEC_SET_STRING(iovec[n++], status);
+ IOVEC_SET_STRING(iovec[n++], "]\n");
+ } else
+ IOVEC_SET_STRING(iovec[n++], "\n");
+
+ writev(fd, iovec, n);
finish:
free(s);
+ free(spaces);
if (fd >= 0)
close_nointr_nofail(fd);
}
-void status_printf(const char *format, ...) {
+void status_printf(const char *status, bool ellipse, const char *format, ...) {
va_list ap;
assert(format);
va_start(ap, format);
- status_vprintf(format, ap);
+ status_vprintf(status, ellipse, format, ap);
va_end(ap);
}
if (!ansi_color && !const_color)
const_color = "1";
- status_printf("\nWelcome to \x1B[%sm%s\x1B[0m!\n\n",
+ status_printf(NULL,
+ false,
+ "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
const_color ? const_color : ansi_color,
const_pretty ? const_pretty : pretty_name);
return r;
}
-int columns(void) {
+int fd_columns(int fd) {
+ struct winsize ws;
+ zero(ws);
+
+ if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+ return -errno;
+
+ if (ws.ws_col <= 0)
+ return -EIO;
+
+ return ws.ws_col;
+}
+
+unsigned columns(void) {
static __thread int parsed_columns = 0;
const char *e;
if (_likely_(parsed_columns > 0))
return parsed_columns;
- if ((e = getenv("COLUMNS")))
+ e = getenv("COLUMNS");
+ if (e)
parsed_columns = atoi(e);
- if (parsed_columns <= 0) {
- struct winsize ws;
- zero(ws);
-
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
- parsed_columns = ws.ws_col;
- }
+ if (parsed_columns <= 0)
+ parsed_columns = fd_columns(STDOUT_FILENO);
if (parsed_columns <= 0)
parsed_columns = 80;
a.st_ino != b.st_ino;
}
-char *ellipsize(const char *s, unsigned length, unsigned percent) {
- size_t l, x;
+char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+ size_t x;
char *r;
assert(s);
assert(percent <= 100);
- assert(length >= 3);
+ assert(new_length >= 3);
- l = strlen(s);
+ if (old_length <= 3 || old_length <= new_length)
+ return strndup(s, old_length);
- if (l <= 3 || l <= length)
- return strdup(s);
-
- if (!(r = new0(char, length+1)))
+ r = new0(char, new_length+1);
+ if (!r)
return r;
- x = (length * percent) / 100;
+ x = (new_length * percent) / 100;
- if (x > length - 3)
- x = length - 3;
+ if (x > new_length - 3)
+ x = new_length - 3;
memcpy(r, s, x);
r[x] = '.';
r[x+1] = '.';
r[x+2] = '.';
memcpy(r + x + 3,
- s + l - (length - x - 3),
- length - x - 3);
+ s + old_length - (new_length - x - 3),
+ new_length - x - 3);
return r;
}
+char *ellipsize(const char *s, size_t length, unsigned percent) {
+ return ellipsize_mem(s, strlen(s), length, percent);
+}
+
int touch(const char *path) {
int fd;
return i;
}
-const char *default_term_for_tty(const char *tty) {
+bool tty_is_vc_resolve(const char *tty) {
char *active = NULL;
- const char *term;
+ bool b;
assert(tty);
if (startswith(tty, "/dev/"))
tty += 5;
- /* Resolve where /dev/console is pointing when determining
- * TERM */
+ /* Resolve where /dev/console is pointing to */
if (streq(tty, "console"))
if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
/* If multiple log outputs are configured the
* last one is what /dev/console points to */
- if ((tty = strrchr(active, ' ')))
+ tty = strrchr(active, ' ');
+ if (tty)
tty++;
else
tty = active;
}
- term = tty_is_vc(tty) ? "TERM=linux" : "TERM=vt100";
+ b = tty_is_vc(tty);
free(active);
- return term;
+ return b;
}
-bool dirent_is_file(struct dirent *de) {
+const char *default_term_for_tty(const char *tty) {
+ assert(tty);
+
+ return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt100";
+}
+
+bool dirent_is_file(const struct dirent *de) {
assert(de);
if (ignore_file(de->d_name))
return true;
}
+bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
+ assert(de);
+
+ if (!dirent_is_file(de))
+ return false;
+
+ return endswith(de->d_name, suffix);
+}
+
void execute_directory(const char *directory, DIR *d, char *argv[]) {
DIR *_d = NULL;
struct dirent *de;
*p += k;
}
+void skip_syslog_pid(char **buf) {
+ char *p;
+
+ assert(buf);
+ assert(*buf);
+
+ p = *buf;
+
+ if (*p != '[')
+ return;
+
+ p++;
+ p += strspn(p, "0123456789");
+
+ if (*p != ']')
+ return;
+
+ p++;
+
+ *buf = p;
+}
+
+void skip_syslog_date(char **buf) {
+ enum {
+ LETTER,
+ SPACE,
+ NUMBER,
+ SPACE_OR_NUMBER,
+ COLON
+ } sequence[] = {
+ LETTER, LETTER, LETTER,
+ SPACE,
+ SPACE_OR_NUMBER, NUMBER,
+ SPACE,
+ SPACE_OR_NUMBER, NUMBER,
+ COLON,
+ SPACE_OR_NUMBER, NUMBER,
+ COLON,
+ SPACE_OR_NUMBER, NUMBER,
+ SPACE
+ };
+
+ char *p;
+ unsigned i;
+
+ assert(buf);
+ assert(*buf);
+
+ p = *buf;
+
+ for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
+
+ if (!*p)
+ return;
+
+ switch (sequence[i]) {
+
+ case SPACE:
+ if (*p != ' ')
+ return;
+ break;
+
+ case SPACE_OR_NUMBER:
+ if (*p == ' ')
+ break;
+
+ /* fall through */
+
+ case NUMBER:
+ if (*p < '0' || *p > '9')
+ return;
+
+ break;
+
+ case LETTER:
+ if (!(*p >= 'A' && *p <= 'Z') &&
+ !(*p >= 'a' && *p <= 'z'))
+ return;
+
+ break;
+
+ case COLON:
+ if (*p != ':')
+ return;
+ break;
+
+ }
+ }
+
+ *buf = p;
+}
+
int have_effective_cap(int value) {
cap_t cap;
cap_flag_value_t fv;
return pollfd.revents & POLLHUP;
}
+int fd_wait_for_event(int fd, int event) {
+ struct pollfd pollfd;
+ int r;
+
+ zero(pollfd);
+ pollfd.fd = fd;
+ pollfd.events = event;
+
+ r = poll(&pollfd, 1, -1);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents;
+}
+
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
FILE *f;
char *t;
return 0;
}
-
-static int file_is_conf(const struct dirent *d, const char *suffix) {
- assert(d);
-
- if (ignore_file(d->d_name))
- return 0;
-
- if (d->d_type != DT_REG &&
- d->d_type != DT_LNK &&
- d->d_type != DT_UNKNOWN)
- return 0;
-
- return endswith(d->d_name, suffix);
-}
-
static int files_add(Hashmap *h, const char *path, const char *suffix) {
DIR *dir;
struct dirent buffer, *de;
if (!de)
break;
- if (!file_is_conf(de, suffix))
+ if (!dirent_is_file_with_suffix(de, suffix))
continue;
if (asprintf(&p, "%s/%s", path, de->d_name) < 0) {
}
int audit_session_from_pid(pid_t pid, uint32_t *id) {
- char *p, *s;
+ char *s;
uint32_t u;
int r;
- assert(pid >= 1);
assert(id);
if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
return -ENOENT;
- if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
- return -ENOMEM;
+ if (pid == 0)
+ r = read_one_line_file("/proc/self/sessionid", &s);
+ else {
+ char *p;
+
+ if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
+ return -ENOMEM;
+
+ r = read_one_line_file(p, &s);
+ free(p);
+ }
- r = read_one_line_file(p, &s);
- free(p);
if (r < 0)
return r;
return 0;
}
+int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
+ char *s;
+ uid_t u;
+ int r;
+
+ assert(uid);
+
+ /* Only use audit login uid if we are executed with sufficient
+ * capabilities so that pam_loginuid could do its job. If we
+ * are lacking the CAP_AUDIT_CONTROL capabality we most likely
+ * are being run in a container and /proc/self/loginuid is
+ * useless since it probably contains a uid of the host
+ * system. */
+
+ if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
+ return -ENOENT;
+
+ if (pid == 0)
+ r = read_one_line_file("/proc/self/loginuid", &s);
+ else {
+ char *p;
+
+ if (asprintf(&p, "/proc/%lu/loginuid", (unsigned long) pid) < 0)
+ return -ENOMEM;
+
+ r = read_one_line_file(p, &s);
+ free(p);
+ }
+
+ if (r < 0)
+ return r;
+
+ r = parse_uid(s, &u);
+ free(s);
+
+ if (r < 0)
+ return r;
+
+ if (u == (uid_t) -1)
+ return -ENOENT;
+
+ *uid = (uid_t) u;
+ return 0;
+}
+
bool display_is_local(const char *display) {
assert(display);
return 0;
}
+int prot_from_flags(int flags) {
+
+ switch (flags & O_ACCMODE) {
+
+ case O_RDONLY:
+ return PROT_READ;
+
+ case O_WRONLY:
+ return PROT_WRITE;
+
+ case O_RDWR:
+ return PROT_READ|PROT_WRITE;
+
+ default:
+ return -EINVAL;
+ }
+}
+
unsigned long cap_last_cap(void) {
static __thread unsigned long saved;
static __thread bool valid = false;
return p;
}
+
+char *format_bytes(char *buf, size_t l, off_t t) {
+ unsigned i;
+
+ static const struct {
+ const char *suffix;
+ off_t factor;
+ } table[] = {
+ { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+ { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+ { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
+ { "G", 1024ULL*1024ULL*1024ULL },
+ { "M", 1024ULL*1024ULL },
+ { "K", 1024ULL },
+ };
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+
+ if (t >= table[i].factor) {
+ snprintf(buf, l,
+ "%llu.%llu%s",
+ (unsigned long long) (t / table[i].factor),
+ (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL),
+ table[i].suffix);
+
+ goto finish;
+ }
+ }
+
+ snprintf(buf, l, "%lluB", (unsigned long long) t);
+
+finish:
+ buf[l-1] = 0;
+ return buf;
+
+}
+
+void* memdup(const void *p, size_t l) {
+ void *r;
+
+ assert(p);
+
+ r = malloc(l);
+ if (!r)
+ return NULL;
+
+ memcpy(r, p, l);
+ return r;
+}