char *resolve_dev_console(char **active) { char *tty; /* Resolve where /dev/console is pointing to, if /sys is actually ours * (i.e. not read-only-mounted which is a sign for container setups) */ if (path_is_read_only_fs("/sys") > 0) return NULL; if (read_one_line_file("/sys/class/tty/console/active", active) < 0) return NULL; /* If multiple log outputs are configured the last one is what * /dev/console points to */ tty = strrchr(*active, ' '); if (tty) tty++; else tty = *active; if (streq(tty, "tty0")) { char *tmp; /* Get the active VC (e.g. tty1) */ if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) { free(*active); tty = *active = tmp; } } return tty; }
static int condition_test_path_is_read_write(Condition *c) { assert(c); assert(c->parameter); assert(c->type == CONDITION_PATH_IS_READ_WRITE); return path_is_read_only_fs(c->parameter) <= 0; }
static int condition_test_needs_update(Condition *c) { const char *p; struct stat usr, other; assert(c); assert(c->parameter); assert(c->type == CONDITION_NEEDS_UPDATE); /* If the file system is read-only we shouldn't suggest an update */ if (path_is_read_only_fs(c->parameter) > 0) return false; /* Any other failure means we should allow the condition to be true, * so that we rather invoke too many update tools then too * few. */ if (!path_is_absolute(c->parameter)) return true; p = strjoina(c->parameter, "/.updated"); if (lstat(p, &other) < 0) return true; if (lstat("/usr/", &usr) < 0) return true; return usr.st_mtim.tv_sec > other.st_mtim.tv_sec || (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec); }
static int parse_fstab(bool initrd) { _cleanup_endmntent_ FILE *f = NULL; const char *fstab_path; struct mntent *me; int r = 0; fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab"; f = setmntent(fstab_path, "re"); if (!f) { if (errno == ENOENT) return 0; log_error_errno(errno, "Failed to open %s: %m", fstab_path); return -errno; } while ((me = getmntent(f))) { _cleanup_free_ char *where = NULL, *what = NULL; bool noauto, nofail; int k; if (initrd && !mount_in_initrd(me)) continue; what = fstab_node_to_udev_node(me->mnt_fsname); if (!what) return log_oom(); if (is_device_path(what) && path_is_read_only_fs("sys") > 0) { log_info("Running in a container, ignoring fstab device entry for %s.", what); continue; } where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir); if (!where) return log_oom(); if (is_path(where)) path_kill_slashes(where); noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0"); nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0"); log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s", what, where, me->mnt_type, yes_no(noauto), yes_no(nofail)); if (streq(me->mnt_type, "swap")) k = add_swap(what, me, noauto, nofail); else { bool automount; const char *post; automount = fstab_test_option(me->mnt_opts, "comment=systemd.automount\0" "x-systemd.automount\0"); if (initrd) post = SPECIAL_INITRD_FS_TARGET; else if (mount_in_initrd(me)) post = SPECIAL_INITRD_ROOT_FS_TARGET; else if (mount_is_network(me)) post = SPECIAL_REMOTE_FS_TARGET; else post = SPECIAL_LOCAL_FS_TARGET; k = add_mount(what, where, me->mnt_type, me->mnt_opts, me->mnt_passno, noauto, nofail, automount, post, fstab_path); } if (k < 0) r = k; } return r; }
static int condition_test_needs_update(Condition *c) { const char *p; struct stat usr, other; assert(c); assert(c->parameter); assert(c->type == CONDITION_NEEDS_UPDATE); /* If the file system is read-only we shouldn't suggest an update */ if (path_is_read_only_fs(c->parameter) > 0) return false; /* Any other failure means we should allow the condition to be true, * so that we rather invoke too many update tools than too * few. */ if (!path_is_absolute(c->parameter)) return true; p = strjoina(c->parameter, "/.updated"); if (lstat(p, &other) < 0) return true; if (lstat("/usr/", &usr) < 0) return true; /* * First, compare seconds as they are always accurate... */ if (usr.st_mtim.tv_sec != other.st_mtim.tv_sec) return usr.st_mtim.tv_sec > other.st_mtim.tv_sec; /* * ...then compare nanoseconds. * * A false positive is only possible when /usr's nanoseconds > 0 * (otherwise /usr cannot be strictly newer than the target file) * AND the target file's nanoseconds == 0 * (otherwise the filesystem supports nsec timestamps, see stat(2)). */ if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) { _cleanup_free_ char *timestamp_str = NULL; uint64_t timestamp; int r; r = parse_env_file(p, NULL, "TIMESTAMP_NSEC", ×tamp_str, NULL); if (r < 0) { log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); return true; } else if (r == 0) { log_debug("No data in timestamp file '%s', using mtime", p); return true; } r = safe_atou64(timestamp_str, ×tamp); if (r < 0) { log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p); return true; } timespec_store(&other.st_mtim, timestamp); } return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec; }
static bool condition_test(Condition *c) { assert(c); switch(c->type) { case CONDITION_PATH_EXISTS: return (access(c->parameter, F_OK) >= 0) == !c->negate; case CONDITION_PATH_EXISTS_GLOB: return (glob_exists(c->parameter) > 0) == !c->negate; case CONDITION_PATH_IS_DIRECTORY: { struct stat st; if (stat(c->parameter, &st) < 0) return c->negate; return S_ISDIR(st.st_mode) == !c->negate; } case CONDITION_PATH_IS_SYMBOLIC_LINK: { struct stat st; if (lstat(c->parameter, &st) < 0) return c->negate; return S_ISLNK(st.st_mode) == !c->negate; } case CONDITION_PATH_IS_MOUNT_POINT: return (path_is_mount_point(c->parameter, true) > 0) == !c->negate; case CONDITION_PATH_IS_READ_WRITE: return (path_is_read_only_fs(c->parameter) > 0) == c->negate; case CONDITION_DIRECTORY_NOT_EMPTY: { int k; k = dir_is_empty(c->parameter); return !(k == -ENOENT || k > 0) == !c->negate; } case CONDITION_FILE_NOT_EMPTY: { struct stat st; if (stat(c->parameter, &st) < 0) return c->negate; return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate; } case CONDITION_FILE_IS_EXECUTABLE: { struct stat st; if (stat(c->parameter, &st) < 0) return c->negate; return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate; } case CONDITION_KERNEL_COMMAND_LINE: return condition_test_kernel_command_line(c); case CONDITION_VIRTUALIZATION: return condition_test_virtualization(c); case CONDITION_SECURITY: return condition_test_security(c); case CONDITION_CAPABILITY: return condition_test_capability(c); case CONDITION_HOST: return condition_test_host(c); case CONDITION_AC_POWER: return condition_test_ac_power(c); case CONDITION_ARCHITECTURE: return condition_test_architecture(c); case CONDITION_NEEDS_UPDATE: return condition_test_needs_update(c); case CONDITION_FIRST_BOOT: return condition_test_first_boot(c); case CONDITION_NULL: return !c->negate; default: assert_not_reached("Invalid condition type."); } }