static unsigned routes_max(void) { static thread_local unsigned cached = 0; _cleanup_free_ char *s4 = NULL, *s6 = NULL; unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY; if (cached > 0) return cached; if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) { truncate_nl(s4); if (safe_atou(s4, &val4) >= 0 && val4 == 2147483647U) /* This is the default "no limit" value in the kernel */ val4 = ROUTES_DEFAULT_MAX_PER_FAMILY; } if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) { truncate_nl(s6); (void) safe_atou(s6, &val6); } cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) + MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6); return cached; }
int read_hostname_config(const char *path, char **hostname) { _cleanup_fclose_ FILE *f = NULL; char l[LINE_MAX]; char *name = NULL; assert(path); assert(hostname); f = fopen(path, "re"); if (!f) return -errno; /* may have comments, ignore them */ FOREACH_LINE(l, f, return -errno) { truncate_nl(l); if (l[0] != '\0' && l[0] != '#') { /* found line with value */ name = hostname_cleanup(l); name = strdup(name); if (!name) return -ENOMEM; break; } } if (!name) /* no non-empty line found */ return -ENOENT; *hostname = name; return 0; }
int clock_is_localtime(const char* adjtime_path) { _cleanup_fclose_ FILE *f; if (adjtime_path == NULL) adjtime_path = "/etc/adjtime"; /* * The third line of adjtime is "UTC" or "LOCAL" or nothing. * # /etc/adjtime * 0.0 0 0 * 0 * UTC */ f = fopen(adjtime_path, "re"); if (f) { char line[LINE_MAX]; bool b; b = fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f); if (!b) /* less than three lines -> default to UTC */ return 0; truncate_nl(line); return streq(line, "LOCAL"); } else if (errno != ENOENT) return -errno; /* adjtime not present -> default to UTC */ return 0; }
static int condition_test_capability(Condition *c) { _cleanup_fclose_ FILE *f = NULL; int value; char line[LINE_MAX]; unsigned long long capabilities = -1; assert(c); assert(c->parameter); assert(c->type == CONDITION_CAPABILITY); /* If it's an invalid capability, we don't have it */ value = capability_from_name(c->parameter); if (value < 0) return -EINVAL; /* If it's a valid capability we default to assume * that we have it */ f = fopen("/proc/self/status", "re"); if (!f) return -errno; while (fgets(line, sizeof(line), f)) { truncate_nl(line); if (startswith(line, "CapBnd:")) { (void) sscanf(line+7, "%llx", &capabilities); break; } } return !!(capabilities & (1ULL << value)); }
int hwclock_is_localtime(void) { _cleanup_fclose_ FILE *f; /* * The third line of adjtime is "UTC" or "LOCAL" or nothing. * # /etc/adjtime * 0.0 0 0 * 0 * UTC */ f = fopen("/etc/adjtime", "re"); if (f) { char line[LINE_MAX]; bool b; b = fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f); if (!b) return -EIO; truncate_nl(line); return streq(line, "LOCAL"); } else if (errno != ENOENT) return -errno; return 0; }
int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; char t[LINE_MAX], *c; assert(fn); assert(line); f = fopen(fn, "re"); if (!f) return -errno; if (!fgets(t, sizeof(t), f)) { if (ferror(f)) return errno ? -errno : -EIO; t[0] = 0; } c = strdup(t); if (!c) return -ENOMEM; truncate_nl(c); *line = c; return 0; }
int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { struct termios old_termios, new_termios; char c, line[LINE_MAX]; assert(f); assert(ret); if (tcgetattr(fileno(f), &old_termios) >= 0) { new_termios = old_termios; new_termios.c_lflag &= ~ICANON; new_termios.c_cc[VMIN] = 1; new_termios.c_cc[VTIME] = 0; if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) { size_t k; if (t != USEC_INFINITY) { if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) { tcsetattr(fileno(f), TCSADRAIN, &old_termios); return -ETIMEDOUT; } } k = fread(&c, 1, 1, f); tcsetattr(fileno(f), TCSADRAIN, &old_termios); if (k <= 0) return -EIO; if (need_nl) *need_nl = c != '\n'; *ret = c; return 0; } } if (t != USEC_INFINITY) { if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) return -ETIMEDOUT; } errno = 0; if (!fgets(line, sizeof(line), f)) return errno ? -errno : -EIO; truncate_nl(line); if (strlen(line) != 1) return -EBADMSG; if (need_nl) *need_nl = false; *ret = line[0]; return 0; }
static int clean_sysvipc_shm(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; bool first = true; int ret = 0; f = fopen("/proc/sysvipc/shm", "re"); if (!f) { if (errno == ENOENT) return 0; log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m"); return -errno; } FOREACH_LINE(line, f, goto fail) { unsigned n_attached; pid_t cpid, lpid; uid_t uid, cuid; gid_t gid, cgid; int shmid; if (first) { first = false; continue; } truncate_nl(line); if (sscanf(line, "%*i %i %*o %*u " PID_FMT " " PID_FMT " %u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT, &shmid, &cpid, &lpid, &n_attached, &uid, &gid, &cuid, &cgid) != 8) continue; if (n_attached > 0) continue; if (uid != delete_uid) continue; if (shmctl(shmid, IPC_RMID, NULL) < 0) { /* Ignore entries that are already deleted */ if (errno == EIDRM || errno == EINVAL) continue; ret = log_warning_errno(errno, "Failed to remove SysV shared memory segment %i: %m", shmid); } } return ret; fail: log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m"); return -errno; }
static int clean_sysvipc_msg(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; bool first = true; int ret = 0; f = fopen("/proc/sysvipc/msg", "re"); if (!f) { if (errno == ENOENT) return 0; log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m"); return -errno; } FOREACH_LINE(line, f, goto fail) { uid_t uid, cuid; gid_t gid, cgid; pid_t cpid, lpid; int msgid; if (first) { first = false; continue; } truncate_nl(line); if (sscanf(line, "%*i %i %*o %*u %*u " PID_FMT " " PID_FMT " " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT, &msgid, &cpid, &lpid, &uid, &gid, &cuid, &cgid) != 7) continue; if (uid != delete_uid) continue; if (msgctl(msgid, IPC_RMID, NULL) < 0) { /* Ignore entries that are already deleted */ if (errno == EIDRM || errno == EINVAL) continue; ret = log_warning_errno(errno, "Failed to remove SysV message queue %i: %m", msgid); } } return ret; fail: log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m"); return -errno; }
static int clean_sysvipc_sem(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; bool first = true; int ret = 0; f = fopen("/proc/sysvipc/sem", "re"); if (!f) { if (errno == ENOENT) return 0; log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m"); return -errno; } FOREACH_LINE(line, f, goto fail) { uid_t uid, cuid; gid_t gid, cgid; int semid; if (first) { first = false; continue; } truncate_nl(line); if (sscanf(line, "%*i %i %*o %*u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT, &semid, &uid, &gid, &cuid, &cgid) != 5) continue; if (uid != delete_uid) continue; if (semctl(semid, 0, IPC_RMID) < 0) { /* Ignore entries that are already deleted */ if (errno == EIDRM || errno == EINVAL) continue; ret = log_warning_errno(errno, "Failed to remove SysV semaphores object %i: %m", semid); } } return ret; fail: log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m"); return -errno; }
static bool promote_secondaries_enabled(const char *ifname) { _cleanup_free_ char *promote_secondaries_sysctl = NULL; char *promote_secondaries_path; int r; promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries"); r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl); if (r < 0) { log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path); return false; } truncate_nl(promote_secondaries_sysctl); r = parse_boolean(promote_secondaries_sysctl); if (r < 0) log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl); return r > 0; }
int ask_string(char **ret, const char *text, ...) { assert(ret); assert(text); for (;;) { char line[LINE_MAX]; va_list ap; if (on_tty()) fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); if (on_tty()) fputs(ANSI_NORMAL, stdout); fflush(stdout); errno = 0; if (!fgets(line, sizeof(line), stdin)) return errno ? -errno : -EIO; if (!endswith(line, "\n")) putchar('\n'); else { char *s; if (isempty(line)) continue; truncate_nl(line); s = strdup(line); if (!s) return -ENOMEM; *ret = s; return 0; } } }
int fs_on_ssd(const char *p) { struct stat st; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; struct udev_device *look_at = NULL; const char *devtype, *rotational, *model, *id; int r; assert(p); if (stat(p, &st) < 0) return -errno; if (major(st.st_dev) == 0) { _cleanup_fclose_ FILE *f = NULL; int mount_id; struct file_handle *h; /* Might be btrfs, which exposes "ssd" as mount flag if it is on ssd. * * We first determine the mount ID here, if we can, * and then lookup the mount ID in mountinfo to find * the mount options. */ h = alloca(MAX_HANDLE_SZ); h->handle_bytes = MAX_HANDLE_SZ; r = name_to_handle_at(AT_FDCWD, p, h, &mount_id, AT_SYMLINK_FOLLOW); if (r < 0) return false; f = fopen("/proc/self/mountinfo", "re"); if (!f) return false; for (;;) { char line[LINE_MAX], *e; _cleanup_free_ char *opts = NULL; int mid; if (!fgets(line, sizeof(line), f)) return false; truncate_nl(line); if (sscanf(line, "%i", &mid) != 1) continue; if (mid != mount_id) continue; e = strstr(line, " - "); if (!e) continue; if (sscanf(e+3, "%*s %*s %ms", &opts) != 1) continue; if (streq(opts, "ssd") || startswith(opts, "ssd,") || endswith(opts, ",ssd") || strstr(opts, ",ssd,")) return true; } return false; } udev = udev_new(); if (!udev) return -ENOMEM; udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); if (!udev_device) return false; devtype = udev_device_get_property_value(udev_device, "DEVTYPE"); if (devtype && streq(devtype, "partition")) look_at = udev_device_get_parent(udev_device); else look_at = udev_device; if (!look_at) return false; /* First, try high-level property */ id = udev_device_get_property_value(look_at, "ID_SSD"); if (id) return streq(id, "1"); /* Second, try kernel attribute */ rotational = udev_device_get_sysattr_value(look_at, "queue/rotational"); if (rotational) return streq(rotational, "0"); /* Finally, fallback to heuristics */ look_at = udev_device_get_parent(look_at); if (!look_at) return false; model = udev_device_get_sysattr_value(look_at, "model"); if (model) return !!strstr(model, "SSD"); return false; }
/* Go through the file and parse each line */ int config_parse(const char *unit, const char *filename, FILE *f, const char *sections, ConfigItemLookup lookup, const void *table, bool relaxed, bool allow_include, bool warn, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false; int r; assert(filename); assert(lookup); if (!f) { f = ours = fopen(filename, "re"); if (!f) { /* Only log on request, except for ENOENT, * since we return 0 to the caller. */ if (warn || errno == ENOENT) log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; } } fd_warn_permissions(filename, fileno(f)); while (!feof(f)) { char l[LINE_MAX], *p, *c = NULL, *e; bool escaped = false; if (!fgets(l, sizeof(l), f)) { if (feof(f)) break; log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); return -errno; } truncate_nl(l); if (continuation) { c = strappend(continuation, l); if (!c) { if (warn) log_oom(); return -ENOMEM; } continuation = mfree(continuation); p = c; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (c) continuation = c; else { continuation = strdup(l); if (!continuation) { if (warn) log_oom(); return -ENOMEM; } } continue; } r = parse_line(unit, filename, ++line, sections, lookup, table, relaxed, allow_include, §ion, §ion_line, §ion_ignored, p, userdata); free(c); if (r < 0) { if (warn) log_warning_errno(r, "Failed to parse file '%s': %m", filename); return r; } } return 0; }
int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { uint64_t missing; int r; assert(c); assert(c->allocated); missing = mask & ~c->mask; if (missing == 0) return 0; /* Try to retrieve PID from creds if it wasn't passed to us */ if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID)) pid = c->pid; if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) tid = c->pid; /* Without pid we cannot do much... */ if (pid <= 0) return 0; if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; const char *p; p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); if (!f) return errno == ENOENT ? -ESRCH : -errno; FOREACH_LINE(line, f, return -errno) { truncate_nl(line); if (missing & SD_BUS_CREDS_UID) { p = startswith(line, "Uid:"); if (p) { unsigned long uid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu", &uid) != 1) return -EIO; c->uid = (uid_t) uid; c->mask |= SD_BUS_CREDS_UID; continue; } } if (missing & SD_BUS_CREDS_GID) { p = startswith(line, "Gid:"); if (p) { unsigned long gid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu", &gid) != 1) return -EIO; c->gid = (uid_t) gid; c->mask |= SD_BUS_CREDS_GID; continue; } } if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) { p = startswith(line, "CapEff:"); if (p) { r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS; continue; } } if (missing & SD_BUS_CREDS_PERMITTED_CAPS) { p = startswith(line, "CapPrm:"); if (p) { r = parse_caps(c, CAP_OFFSET_PERMITTED, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_PERMITTED_CAPS; continue; } } if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) { p = startswith(line, "CapInh:"); if (p) { r = parse_caps(c, CAP_OFFSET_INHERITABLE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS; continue; } } if (missing & SD_BUS_CREDS_BOUNDING_CAPS) { p = startswith(line, "CapBnd:"); if (p) { r = parse_caps(c, CAP_OFFSET_BOUNDING, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_BOUNDING_CAPS; continue; } } } }
/* Go through the file and parse each line */ int config_parse(const char *unit, const char *filename, FILE *f, const char *sections, ConfigItemLookup lookup, void *table, bool relaxed, bool allow_include, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; int r; assert(filename); assert(lookup); if (!f) { f = ours = fopen(filename, "re"); if (!f) { log_error("Failed to open configuration file '%s': %m", filename); return -errno; } } fd_warn_permissions(filename, fileno(f)); while (!feof(f)) { char l[LINE_MAX], *p, *c = NULL, *e; bool escaped = false; if (!fgets(l, sizeof(l), f)) { if (feof(f)) break; log_error("Failed to read configuration file '%s': %m", filename); return -errno; } truncate_nl(l); if (continuation) { c = strappend(continuation, l); if (!c) return -ENOMEM; free(continuation); continuation = NULL; p = c; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (c) continuation = c; else { continuation = strdup(l); if (!continuation) return -ENOMEM; } continue; } r = parse_line(unit, filename, ++line, sections, lookup, table, relaxed, allow_include, §ion, §ion_line, p, userdata); free(c); if (r < 0) return r; } return 0; }
static void load_unix_sockets(void) { FILE *f = NULL; char line[LINE_MAX]; if (unix_sockets) return; /* We maintain a cache of the sockets we found in * /proc/net/unix to speed things up a little. */ unix_sockets = set_new(string_hash_func, string_compare_func); if (!unix_sockets) return; f = fopen("/proc/net/unix", "re"); if (!f) return; /* Skip header */ if (!fgets(line, sizeof(line), f)) goto fail; for (;;) { char *p, *s; int k; if (!fgets(line, sizeof(line), f)) break; truncate_nl(line); p = strchr(line, ':'); if (!p) continue; if (strlen(p) < 37) continue; p += 37; p += strspn(p, WHITESPACE); p += strcspn(p, WHITESPACE); /* skip one more word */ p += strspn(p, WHITESPACE); if (*p != '/') continue; s = strdup(p); if (!s) goto fail; path_kill_slashes(s); k = set_put(unix_sockets, s); if (k < 0) { free(s); if (k != -EEXIST) goto fail; } } fclose(f); return; fail: set_free_free(unix_sockets); unix_sockets = NULL; if (f) fclose(f); }
int cg_get_by_pid(const char *controller, pid_t pid, char **path) { int r; char *p = NULL; FILE *f; char *fs; size_t cs; assert(controller); assert(path); assert(pid >= 0); if (pid == 0) pid = getpid(); if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0) return -ENOMEM; f = fopen(fs, "re"); free(fs); if (!f) return errno == ENOENT ? -ESRCH : -errno; cs = strlen(controller); while (!feof(f)) { char line[LINE_MAX]; char *l; errno = 0; if (!(fgets(line, sizeof(line), f))) { if (feof(f)) break; r = errno ? -errno : -EIO; goto finish; } truncate_nl(line); if (!(l = strchr(line, ':'))) continue; l++; if (strncmp(l, controller, cs) != 0) continue; if (l[cs] != ':') continue; if (!(p = strdup(l + cs + 1))) { r = -ENOMEM; goto finish; } *path = p; r = 0; goto finish; } r = -ENOENT; finish: fclose(f); return r; }
static int test_string_util_truncate_nl_newline_first_char(void) { char str[] = "\nhello, world!"; truncate_nl(str); return strcmp(str, ""); }
int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *payload = NULL; unsigned n = 0; sd_id128_t id; char language[32]; bool got_id = false, empty_line = true; int r; assert(h); assert(sb); assert(path); f = fopen(path, "re"); if (!f) { log_error("Failed to open file %s: %m", path); return -errno; } for (;;) { char line[LINE_MAX]; size_t a, b, c; char *t; if (!fgets(line, sizeof(line), f)) { if (feof(f)) break; log_error("Failed to read file %s: %m", path); return -errno; } n++; truncate_nl(line); if (line[0] == 0) { empty_line = true; continue; } if (strchr(COMMENTS "\n", line[0])) continue; if (empty_line && strlen(line) >= 2+1+32 && line[0] == '-' && line[1] == '-' && line[2] == ' ' && (line[2+1+32] == ' ' || line[2+1+32] == '\0')) { bool with_language; sd_id128_t jd; /* New entry */ with_language = line[2+1+32] != '\0'; line[2+1+32] = '\0'; if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { if (got_id) { r = finish_item(h, sb, id, language, payload); if (r < 0) return r; } if (with_language) { t = strstrip(line + 2 + 1 + 32 + 1); c = strlen(t); if (c <= 0) { log_error("[%s:%u] Language too short.", path, n); return -EINVAL; } if (c > sizeof(language) - 1) { log_error("[%s:%u] language too long.", path, n); return -EINVAL; } strscpy(language, sizeof(language), t); } else language[0] = '\0'; got_id = true; empty_line = false; id = jd; if (payload) payload[0] = '\0'; continue; } } /* Payload */ if (!got_id) { log_error("[%s:%u] Got payload before ID.", path, n); return -EINVAL; } a = payload ? strlen(payload) : 0; b = strlen(line); c = a + (empty_line ? 1 : 0) + b + 1 + 1; t = realloc(payload, c); if (!t) return log_oom(); if (empty_line) { t[a] = '\n'; memcpy(t + a + 1, line, b); t[a+b+1] = '\n'; t[a+b+2] = 0; } else { memcpy(t + a, line, b); t[a+b] = '\n'; t[a+b+1] = 0; } payload = t; empty_line = false; } if (got_id) { r = finish_item(h, sb, id, language, payload); if (r < 0) return r; } return 0; }
static int test_string_util_truncate_nl_null(void) { truncate_nl(NULL); /* make sure it doesn't segfault */ return 0; }
static int unpack_file(FILE *pack) { _cleanup_close_ int fd = -1; char fn[PATH_MAX]; bool any = false; struct stat st; uint64_t inode; assert(pack); if (!fgets(fn, sizeof(fn), pack)) return 0; char_array_0(fn); truncate_nl(fn); fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); if (fd < 0) { if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP) log_warning("open(%s) failed: %m", fn); } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) fd = safe_close(fd); if (fread(&inode, sizeof(inode), 1, pack) != 1) { log_error("Premature end of pack file."); return -EIO; } if (fd >= 0) { /* If the inode changed the file got deleted, so just * ignore this entry */ if (st.st_ino != (uint64_t) inode) fd = safe_close(fd); } for (;;) { uint32_t b, c; if (fread(&b, sizeof(b), 1, pack) != 1 || fread(&c, sizeof(c), 1, pack) != 1) { log_error("Premature end of pack file."); return -EIO; } if (b == 0 && c == 0) break; if (c <= b) { log_error("Invalid pack file."); return -EIO; } log_debug("%s: page %u to %u", fn, b, c); any = true; if (fd >= 0) { if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) { log_warning("posix_fadvise() failed: %m"); return -errno; } } } if (!any && fd >= 0) { /* if no range is encoded in the pack file this is * intended to mean that the whole file shall be * read */ if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) { log_warning("posix_fadvise() failed: %m"); return -errno; } } return 0; }
static int test_string_util_truncate_nl_empty_string(void) { char str[] = ""; truncate_nl(str); return strcmp(str, ""); }
int change_uid_gid(const char *user, char **_home) { char line[LINE_MAX], *x, *u, *g, *h; const char *word, *state; _cleanup_free_ uid_t *uids = NULL; _cleanup_free_ char *home = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -1; unsigned n_uids = 0; size_t sz = 0, l; uid_t uid; gid_t gid; pid_t pid; int r; assert(_home); if (!user || streq(user, "root") || streq(user, "0")) { /* Reset everything fully to 0, just in case */ r = reset_uid_gid(); if (r < 0) return log_error_errno(r, "Failed to become root: %m"); *_home = NULL; return 0; } /* First, get user credentials */ fd = spawn_getent("passwd", user, &pid); if (fd < 0) return fd; f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent passwd", pid, true); x = strchr(line, ':'); if (!x) { log_error("/etc/passwd entry has invalid user field."); return -EIO; } u = strchr(x+1, ':'); if (!u) { log_error("/etc/passwd entry has invalid password field."); return -EIO; } u++; g = strchr(u, ':'); if (!g) { log_error("/etc/passwd entry has invalid UID field."); return -EIO; } *g = 0; g++; x = strchr(g, ':'); if (!x) { log_error("/etc/passwd entry has invalid GID field."); return -EIO; } *x = 0; h = strchr(x+1, ':'); if (!h) { log_error("/etc/passwd entry has invalid GECOS field."); return -EIO; } h++; x = strchr(h, ':'); if (!x) { log_error("/etc/passwd entry has invalid home directory field."); return -EIO; } *x = 0; r = parse_uid(u, &uid); if (r < 0) { log_error("Failed to parse UID of user."); return -EIO; } r = parse_gid(g, &gid); if (r < 0) { log_error("Failed to parse GID of user."); return -EIO; } home = strdup(h); if (!home) return log_oom(); /* Second, get group memberships */ fd = spawn_getent("initgroups", user, &pid); if (fd < 0) return fd; fclose(f); f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent initgroups", pid, true); /* Skip over the username and subsequent separator whitespace */ x = line; x += strcspn(x, WHITESPACE); x += strspn(x, WHITESPACE); FOREACH_WORD(word, l, x, state) { char c[l+1]; memcpy(c, word, l); c[l] = 0; if (!GREEDY_REALLOC(uids, sz, n_uids+1)) return log_oom(); r = parse_uid(c, &uids[n_uids++]); if (r < 0) { log_error("Failed to parse group data from getent."); return -EIO; } }
static int test_string_util_truncate_nl_newline_middle(void) { char str[] = "hello, \nworld!"; truncate_nl(str); return strcmp(str, "hello, "); }
int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { uint64_t missing; int r; assert(c); assert(c->allocated); if (!(mask & SD_BUS_CREDS_AUGMENT)) return 0; /* Try to retrieve PID from creds if it wasn't passed to us */ if (pid > 0) { c->pid = pid; c->mask |= SD_BUS_CREDS_PID; } else if (c->mask & SD_BUS_CREDS_PID) pid = c->pid; else /* Without pid we cannot do much... */ return 0; /* Try to retrieve TID from creds if it wasn't passed to us */ if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) tid = c->tid; /* Calculate what we shall and can add */ missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT); if (missing == 0) return 0; if (tid > 0) { c->tid = tid; c->mask |= SD_BUS_CREDS_TID; } if (missing & (SD_BUS_CREDS_PPID | SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID | SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID | SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) { _cleanup_fclose_ FILE *f = NULL; const char *p; p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); if (!f) { if (errno == ENOENT) return -ESRCH; else if (errno != EPERM && errno != EACCES) return -errno; } else { char line[LINE_MAX]; FOREACH_LINE(line, f, return -errno) { truncate_nl(line); if (missing & SD_BUS_CREDS_PPID) { p = startswith(line, "PPid:"); if (p) { p += strspn(p, WHITESPACE); /* Explicitly check for PPID 0 (which is the case for PID 1) */ if (!streq(p, "0")) { r = parse_pid(p, &c->ppid); if (r < 0) return r; } else c->ppid = 0; c->mask |= SD_BUS_CREDS_PPID; continue; } } if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) { p = startswith(line, "Uid:"); if (p) { unsigned long uid, euid, suid, fsuid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4) return -EIO; if (missing & SD_BUS_CREDS_UID) c->uid = (uid_t) uid; if (missing & SD_BUS_CREDS_EUID) c->euid = (uid_t) euid; if (missing & SD_BUS_CREDS_SUID) c->suid = (uid_t) suid; if (missing & SD_BUS_CREDS_FSUID) c->fsuid = (uid_t) fsuid; c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID); continue; } } if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) { p = startswith(line, "Gid:"); if (p) { unsigned long gid, egid, sgid, fsgid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4) return -EIO; if (missing & SD_BUS_CREDS_GID) c->gid = (gid_t) gid; if (missing & SD_BUS_CREDS_EGID) c->egid = (gid_t) egid; if (missing & SD_BUS_CREDS_SGID) c->sgid = (gid_t) sgid; if (missing & SD_BUS_CREDS_FSGID) c->fsgid = (gid_t) fsgid; c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID); continue; } } if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { p = startswith(line, "Groups:"); if (p) { size_t allocated = 0; for (;;) { unsigned long g; int n = 0; p += strspn(p, WHITESPACE); if (*p == 0) break; if (sscanf(p, "%lu%n", &g, &n) != 1) return -EIO; if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1)) return -ENOMEM; c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g; p += n; } c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; continue; } } if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) { p = startswith(line, "CapEff:"); if (p) { r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS; continue; } } if (missing & SD_BUS_CREDS_PERMITTED_CAPS) { p = startswith(line, "CapPrm:"); if (p) { r = parse_caps(c, CAP_OFFSET_PERMITTED, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_PERMITTED_CAPS; continue; } } if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) { p = startswith(line, "CapInh:"); if (p) { r = parse_caps(c, CAP_OFFSET_INHERITABLE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS; continue; } } if (missing & SD_BUS_CREDS_BOUNDING_CAPS) { p = startswith(line, "CapBnd:"); if (p) { r = parse_caps(c, CAP_OFFSET_BOUNDING, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_BOUNDING_CAPS; continue; } } } } }
/* Go through the file and parse each line */ int config_parse( const char *filename, FILE *f, const char *sections, ConfigItemLookup lookup, void *table, bool relaxed, void *userdata) { unsigned line = 0; char *section = NULL; int r; bool ours = false; char *continuation = NULL; assert(filename); assert(lookup); if (!f) { f = fopen(filename, "re"); if (!f) { r = -errno; log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); goto finish; } ours = true; } while (!feof(f)) { char l[LINE_MAX], *p, *c = NULL, *e; bool escaped = false; if (!fgets(l, sizeof(l), f)) { if (feof(f)) break; r = -errno; log_error("Failed to read configuration file '%s': %s", filename, strerror(-r)); goto finish; } truncate_nl(l); if (continuation) { c = strappend(continuation, l); if (!c) { r = -ENOMEM; goto finish; } free(continuation); continuation = NULL; p = c; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (c) continuation = c; else { continuation = strdup(l); if (!continuation) { r = -ENOMEM; goto finish; } } continue; } r = parse_line(filename, ++line, sections, lookup, table, relaxed, §ion, p, userdata); free(c); if (r < 0) goto finish; } r = 0; finish: free(section); free(continuation); if (f && ours) fclose(f); return r; }
static int test_string_util_truncate_nl_newline_only(void) { char str[] = "\n"; truncate_nl(str); return strcmp(str, ""); }