int cg_install_release_agent(const char *controller, const char *agent) { char *fs = NULL, *contents = NULL, *line = NULL, *sc; int r; assert(controller); assert(agent); if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0) return r; if ((r = read_one_line_file(fs, &contents)) < 0) goto finish; sc = strstrip(contents); if (sc[0] == 0) { if (asprintf(&line, "%s\n", agent) < 0) { r = -ENOMEM; goto finish; } if ((r = write_one_line_file(fs, line)) < 0) goto finish; } else if (!streq(sc, agent)) { r = -EEXIST; goto finish; } free(fs); fs = NULL; if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) goto finish; free(contents); contents = NULL; if ((r = read_one_line_file(fs, &contents)) < 0) goto finish; sc = strstrip(contents); if (streq(sc, "0")) { if ((r = write_one_line_file(fs, "1\n")) < 0) goto finish; r = 1; } else if (!streq(sc, "1")) { r = -EIO; goto finish; } else r = 0; finish: free(fs); free(contents); free(line); return r; }
int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) { int r; _cleanup_free_ char *path = NULL, *v = NULL; assert(a); b = cgroup_bonding_find_list(b, a->controller); if (!b) return 0; if (a->map_callback) { r = a->map_callback(a->controller, a->name, a->value, &v); if (r < 0) return r; } r = cg_get_path(a->controller, b->path, a->name, &path); if (r < 0) return r; r = write_one_line_file(path, v ? v : a->value); if (r < 0) log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r)); return r; }
int block_bump_request_nr(const char *p) { struct stat st; uint64_t u; char *ap = NULL, *line = NULL; int r; dev_t d; assert(p); if (stat(p, &st) < 0) return -errno; if (major(st.st_dev) == 0) return 0; d = st.st_dev; block_get_whole_disk(d, &d); if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { r= -ENOMEM; goto finish; } r = read_one_line_file(ap, &line); if (r < 0) { if (r == -ENOENT) r = 0; goto finish; } r = safe_atou64(line, &u); if (r >= 0 && u >= BUMP_REQUEST_NR) { r = 0; goto finish; } free(line); line = NULL; if (asprintf(&line, "%lu", (unsigned long) BUMP_REQUEST_NR) < 0) { r = -ENOMEM; goto finish; } r = write_one_line_file(ap, line); if (r < 0) goto finish; log_info("Bumped block_nr parameter of %u:%u to %lu. This is a temporary hack and should be removed one day.", major(d), minor(d), (unsigned long) BUMP_REQUEST_NR); r = 1; finish: free(ap); free(line); return r; }
static int apply_rule(const char *rule) { int r; delete_rule(rule); if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) { log_error("Failed to add binary format: %s", strerror(-r)); return r; } return 0; }
int main(int argc, char *argv[]) { int r = 0; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); if (argc > 1) { int i; for (i = 1; i < argc; i++) { int k; k = apply_file(argv[i], false); if (k < 0 && r == 0) r = k; } } else { char **files, **f; r = conf_files_list(&files, ".conf", "/etc/binfmt.d", "/run/binfmt.d", "/usr/local/lib/binfmt.d", "/usr/lib/binfmt.d", #ifdef HAVE_SPLIT_USR "/lib/binfmt.d", #endif NULL); if (r < 0) { log_error("Failed to enumerate binfmt.d files: %s", strerror(-r)); goto finish; } /* Flush out all rules */ write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1"); STRV_FOREACH(f, files) { int k; k = apply_file(*f, true); if (k < 0 && r == 0) r = k; } strv_free(files); }
static int enable_utf8(int fd) { int r = 0, k; if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0) r = -errno; if (loop_write(fd, "\033%G", 3, false) < 0) r = -errno; k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1"); if (k < 0) r = k; if (r < 0) log_warning("Failed to enable UTF-8: %s", strerror(-r)); return r; }
int main(int argc, char *argv[]) { int r = 0; if (argc > 2) { log_error("This program expects one or no arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); if (argc > 1) { r = apply_file(argv[1], false); } else { char **files, **f; /* Flush out all rules */ write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1"); r = conf_files_list(&files, ".conf", "/run/binfmt.d", "/etc/binfmt.d", "/usr/local/lib/binfmt.d", "/usr/lib/binfmt.d", NULL); if (r < 0) { log_error("Failed to enumerate binfmt.d files: %s", strerror(-r)); goto finish; } STRV_FOREACH(f, files) { int k; k = apply_file(*f, true); if (k < 0 && r == 0) r = k; } strv_free(files); }
int block_set_readahead(const char *p, uint64_t bytes) { struct stat st; char *ap = NULL, *line = NULL; int r; dev_t d; assert(p); assert(bytes); if (stat(p, &st) < 0) return -errno; if (major(st.st_dev) == 0) return 0; d = st.st_dev; block_get_whole_disk(d, &d); if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { r = -ENOMEM; goto finish; } if (asprintf(&line, "%llu", (unsigned long long) bytes / 1024ULL) < 0) { r = -ENOMEM; goto finish; } r = write_one_line_file(ap, line); if (r < 0) goto finish; finish: free(ap); free(line); return r; }
int cg_attach(const char *controller, const char *path, pid_t pid) { char *fs; int r; char c[32]; assert(controller); assert(path); assert(pid >= 0); if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0) return r; if (pid == 0) pid = getpid(); snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid); char_array_0(c); r = write_one_line_file(fs, c); free(fs); return r; }
static int delete_rule(const char *rule) { char *x, *fn = NULL, *e; int r; assert(rule[0]); if (!(x = strdup(rule))) return log_oom(); e = strchrnul(x+1, x[0]); *e = 0; asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1); free(x); if (!fn) return log_oom(); r = write_one_line_file(fn, "-1"); free(fn); return r; }
int main(int argc, char *argv[]) { enum { FD_SOCKET, FD_WALL_TIMER, FD_NOLOGIN_TIMER, FD_SHUTDOWN_TIMER, _FD_MAX }; int r = EXIT_FAILURE, n_fds; int one = 1; struct shutdownd_command c; struct pollfd pollfd[_FD_MAX]; bool exec_shutdown = false, unlink_nologin = false, failed = false; unsigned i; if (getppid() != 1) { log_error("This program should be invoked by init only."); return EXIT_FAILURE; } if (argc > 1) { log_error("This program does not take arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); log_parse_environment(); log_open(); if ((n_fds = sd_listen_fds(true)) < 0) { log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); return EXIT_FAILURE; } if (n_fds != 1) { log_error("Need exactly one file descriptor."); return EXIT_FAILURE; } if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { log_error("SO_PASSCRED failed: %m"); return EXIT_FAILURE; } zero(c); zero(pollfd); pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START; pollfd[FD_SOCKET].events = POLLIN; for (i = 0; i < _FD_MAX; i++) { if (i == FD_SOCKET) continue; pollfd[i].events = POLLIN; if ((pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) { log_error("timerfd_create(): %m"); failed = true; } } if (failed) goto finish; log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid()); sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); do { int k; usec_t n; if (poll(pollfd, _FD_MAX, -1) < 0) { if (errno == EAGAIN || errno == EINTR) continue; log_error("poll(): %m"); goto finish; } n = now(CLOCK_REALTIME); if (pollfd[FD_SOCKET].revents) { if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0) goto finish; else if (k > 0 && c.elapse > 0) { struct itimerspec its; char date[FORMAT_TIMESTAMP_MAX]; if (c.warn_wall) { /* Send wall messages every so often */ zero(its); timespec_store(&its.it_value, when_wall(n, c.elapse)); if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } /* Warn immediately if less than 15 minutes are left */ if (n < c.elapse && n + 15*USEC_PER_MINUTE >= c.elapse) warn_wall(n, &c); } /* Disallow logins 5 minutes prior to shutdown */ zero(its); timespec_store(&its.it_value, when_nologin(c.elapse)); if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } /* Shutdown after the specified time is reached */ zero(its); timespec_store(&its.it_value, c.elapse); if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } sd_notifyf(false, "STATUS=Shutting down at %s...", format_timestamp(date, sizeof(date), c.elapse)); } } if (pollfd[FD_WALL_TIMER].revents) { struct itimerspec its; warn_wall(n, &c); flush_fd(pollfd[FD_WALL_TIMER].fd); /* Restart timer */ zero(its); timespec_store(&its.it_value, when_wall(n, c.elapse)); if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } } if (pollfd[FD_NOLOGIN_TIMER].revents) { int e; log_info("Creating /run/nologin, blocking further logins..."); if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0) log_error("Failed to create /run/nologin: %s", strerror(-e)); else unlink_nologin = true; flush_fd(pollfd[FD_NOLOGIN_TIMER].fd); } if (pollfd[FD_SHUTDOWN_TIMER].revents) { exec_shutdown = true; goto finish; } } while (c.elapse > 0); r = EXIT_SUCCESS; log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid()); finish: for (i = 0; i < _FD_MAX; i++) if (pollfd[i].fd >= 0) close_nointr_nofail(pollfd[i].fd); if (unlink_nologin) unlink("/run/nologin"); if (exec_shutdown) { char sw[3]; sw[0] = '-'; sw[1] = c.mode; sw[2] = 0; execl(SYSTEMCTL_BINARY_PATH, "shutdown", sw, "now", (c.warn_wall && c.wall_message[0]) ? c.wall_message : (c.warn_wall ? NULL : "--no-wall"), NULL); log_error("Failed to execute /sbin/shutdown: %m"); } sd_notify(false, "STATUS=Exiting..."); return r; }
int machine_id_setup(void) { int fd, r; bool writable; struct stat st; char id[34]; /* 32 + \n + \0 */ mode_t m; m = umask(0000); /* We create this 0444, to indicate that this isn't really * something you should ever modify. Of course, since the file * will be owned by root it doesn't matter much, but maybe * people look. */ if ((fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444)) >= 0) writable = true; else { if ((fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { umask(m); log_error("Cannot open /etc/machine-id: %m"); return -errno; } writable = false; } umask(m); if (fstat(fd, &st) < 0) { log_error("fstat() failed: %m"); r = -errno; goto finish; } if (S_ISREG(st.st_mode)) { if (loop_read(fd, id, 32, false) >= 32) { r = 0; goto finish; } } /* Hmm, so, the id currently stored is not useful, then let's * generate one */ if ((r = generate(id)) < 0) goto finish; if (S_ISREG(st.st_mode) && writable) { lseek(fd, 0, SEEK_SET); if (loop_write(fd, id, 33, false) == 33) { r = 0; goto finish; } } close_nointr_nofail(fd); fd = -1; /* Hmm, we couldn't write it? So let's write it to * /run/systemd/machine-id as a replacement */ mkdir_p("/run/systemd", 0755); if ((r = write_one_line_file("/run/systemd/machine-id", id)) < 0) { log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r)); unlink("/run/systemd/machine-id"); goto finish; } /* And now, let's mount it over */ r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0; unlink("/run/systemd/machine-id"); if (r < 0) log_error("Failed to mount /etc/machine-id: %s", strerror(-r)); else log_info("Installed transient /etc/machine-id file."); finish: if (fd >= 0) close_nointr_nofail(fd); return r; }