static int x11_read_data(Context *c) { _cleanup_fclose_ FILE *f; char line[LINE_MAX]; bool in_section = false; int r; context_free_x11(c); f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); if (!f) return errno == ENOENT ? 0 : -errno; while (fgets(line, sizeof(line), f)) { char *l; char_array_0(line); l = strstrip(line); if (l[0] == 0 || l[0] == '#') continue; if (in_section && first_word(l, "Option")) { _cleanup_strv_free_ char **a = NULL; r = strv_split_quoted(&a, l, false); if (r < 0) return r; if (strv_length(a) == 3) { if (streq(a[1], "XkbLayout")) { free_and_replace(&c->x11_layout, a[2]); a[2] = NULL; } else if (streq(a[1], "XkbModel")) { free_and_replace(&c->x11_model, a[2]); a[2] = NULL; } else if (streq(a[1], "XkbVariant")) { free_and_replace(&c->x11_variant, a[2]); a[2] = NULL; } else if (streq(a[1], "XkbOptions")) { free_and_replace(&c->x11_options, a[2]); a[2] = NULL; } } } else if (!in_section && first_word(l, "Section")) { _cleanup_strv_free_ char **a = NULL; r = strv_split_quoted(&a, l, false); if (r < 0) return -ENOMEM; if (strv_length(a) == 2 && streq(a[1], "InputClass")) in_section = true; } else if (in_section && first_word(l, "EndSection")) in_section = false; } return 0; }
static int acquire_esp( bool unprivileged_mode, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid) { char *np; int r; /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own, * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=) * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that * --list and --status work too, without noise about this). */ r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid); if (r == -ENOKEY) return log_error_errno(r, "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n" "Alternatively, use --path= to specify path to mount point."); if (r < 0) return r; free_and_replace(arg_path, np); log_debug("Using EFI System Partition at %s.", arg_path); return 0; }
static void locale_simplify(Context *c) { int p; for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) free_and_replace(&c->locale[p], NULL); }
static int merge_env_file_push( const char *filename, unsigned line, const char *key, char *value, void *userdata, int *n_pushed) { char ***env = userdata; char *expanded_value; assert(env); if (!value) { log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key); return 0; } if (!env_name_is_valid(key)) { log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key); free(value); return 0; } expanded_value = replace_env(value, *env, REPLACE_ENV_USE_ENVIRONMENT| REPLACE_ENV_ALLOW_BRACELESS| REPLACE_ENV_ALLOW_EXTENDED); if (!expanded_value) return -ENOMEM; free_and_replace(value, expanded_value); return load_env_file_push(filename, line, key, value, env, n_pushed); }
int config_parse_network_zone( const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { Settings *settings = data; _cleanup_free_ char *j = NULL; assert(filename); assert(lvalue); assert(rvalue); j = strappend("vz-", rvalue); if (!ifname_valid(j)) { log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name %s, ignoring: %m", rvalue); return 0; } free_and_replace(settings->network_zone, j); return 0; }
static void client_context_read_basic(ClientContext *c) { char *t; assert(c); assert(pid_is_valid(c->pid)); if (get_process_comm(c->pid, &t) >= 0) free_and_replace(c->comm, t); if (get_process_exe(c->pid, &t) >= 0) free_and_replace(c->exe, t); if (get_process_cmdline(c->pid, 0, false, &t) >= 0) free_and_replace(c->cmdline, t); if (get_process_capeff(c->pid, &t) >= 0) free_and_replace(c->capeff, t); }
static int swap_list_get(MountPoint **head) { _cleanup_fclose_ FILE *proc_swaps = NULL; unsigned int i; int r; assert(head); proc_swaps = fopen("/proc/swaps", "re"); if (!proc_swaps) return (errno == ENOENT) ? 0 : -errno; (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n"); for (i = 2;; i++) { MountPoint *swap; _cleanup_free_ char *dev = NULL, *d = NULL; int k; k = fscanf(proc_swaps, "%ms " /* device/file */ "%*s " /* type of swap */ "%*s " /* swap size */ "%*s " /* used */ "%*s\n", /* priority */ &dev); if (k != 1) { if (k == EOF) break; log_warning("Failed to parse /proc/swaps:%u.", i); continue; } if (endswith(dev, " (deleted)")) continue; r = cunescape(dev, UNESCAPE_RELAX, &d); if (r < 0) return r; swap = new0(MountPoint, 1); if (!swap) return -ENOMEM; free_and_replace(swap->path, d); LIST_PREPEND(mount_point, *head, swap); } return 0; }
static int raw_pull_maybe_convert_qcow2(RawPull *i) { _cleanup_close_ int converted_fd = -1; _cleanup_free_ char *t = NULL; int r; assert(i); assert(i->raw_job); r = qcow2_detect(i->raw_job->disk_fd); if (r < 0) return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m"); if (r == 0) return 0; /* This is a QCOW2 image, let's convert it */ r = tempfn_random(i->final_path, NULL, &t); if (r < 0) return log_oom(); converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664); if (converted_fd < 0) return log_error_errno(errno, "Failed to create %s: %m", t); r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); r = qcow2_convert(i->raw_job->disk_fd, converted_fd); if (r < 0) { unlink(t); return log_error_errno(r, "Failed to convert qcow2 image: %m"); } (void) unlink(i->temp_path); free_and_replace(i->temp_path, t); safe_close(i->raw_job->disk_fd); i->raw_job->disk_fd = TAKE_FD(converted_fd); return 1; }
static int client_context_read_label( ClientContext *c, const char *label, size_t label_size) { assert(c); assert(pid_is_valid(c->pid)); assert(label_size == 0 || label); if (label_size > 0) { char *l; /* If we got an SELinux label passed in it counts. */ l = newdup_suffix0(char, label, label_size); if (!l) return -ENOMEM; free_and_replace(c->label, l); c->label_size = label_size; }
static void context_free_locale(Context *c) { int p; for (p = 0; p < _LOCALE_MAX; p++) free_and_replace(&c->locale[p], NULL); }
static void context_free_vconsole(Context *c) { free_and_replace(&c->vc_keymap, NULL); free_and_replace(&c->vc_keymap_toggle, NULL); }
static void context_free_x11(Context *c) { free_and_replace(&c->x11_layout, NULL); free_and_replace(&c->x11_model, NULL); free_and_replace(&c->x11_variant, NULL); free_and_replace(&c->x11_options, NULL); }
int x11_read_data(Context *c, sd_bus_message *m) { _cleanup_fclose_ FILE *f = NULL; bool in_section = false; char line[LINE_MAX]; struct stat st; usec_t t; int r; /* Do not try to re-read the file within single bus operation. */ if (m) { if (m == c->x11_cache) return 0; sd_bus_message_unref(c->x11_cache); c->x11_cache = sd_bus_message_ref(m); } if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) { if (errno != ENOENT) return -errno; c->x11_mtime = USEC_INFINITY; context_free_x11(c); return 0; } /* If mtime is not changed, then we do not need to re-read */ t = timespec_load(&st.st_mtim); if (c->x11_mtime != USEC_INFINITY && t == c->x11_mtime) return 0; c->x11_mtime = t; context_free_x11(c); f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); if (!f) return -errno; while (fgets(line, sizeof(line), f)) { char *l; char_array_0(line); l = strstrip(line); if (IN_SET(l[0], 0, '#')) continue; if (in_section && first_word(l, "Option")) { _cleanup_strv_free_ char **a = NULL; r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return r; if (strv_length(a) == 3) { char **p = NULL; if (streq(a[1], "XkbLayout")) p = &c->x11_layout; else if (streq(a[1], "XkbModel")) p = &c->x11_model; else if (streq(a[1], "XkbVariant")) p = &c->x11_variant; else if (streq(a[1], "XkbOptions")) p = &c->x11_options; if (p) { free_and_replace(*p, a[2]); } } } else if (!in_section && first_word(l, "Section")) { _cleanup_strv_free_ char **a = NULL; r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return -ENOMEM; if (strv_length(a) == 2 && streq(a[1], "InputClass")) in_section = true; } else if (in_section && first_word(l, "EndSection")) in_section = false; } return 0; }
/* Parse a single logical line */ static int parse_line( const char* unit, const char *filename, unsigned line, const char *sections, ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, char **section, unsigned *section_line, bool *section_ignored, char *l, void *userdata) { char *e, *include; assert(filename); assert(line > 0); assert(lookup); assert(l); l = strstrip(l); if (!*l) return 0; if (strchr(COMMENTS "\n", *l)) return 0; include = first_word(l, ".include"); if (include) { _cleanup_free_ char *fn = NULL; /* .includes are a bad idea, we only support them here * for historical reasons. They create cyclic include * problems and make it difficult to detect * configuration file changes with an easy * stat(). Better approaches, such as .d/ drop-in * snippets exist. * * Support for them should be eventually removed. */ if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) { log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring."); return 0; } log_syntax(unit, LOG_WARNING, filename, line, 0, ".include directives are deprecated, and support for them will be removed in a future version of systemd. " "Please use drop-in files instead."); fn = file_in_same_dir(filename, strstrip(include)); if (!fn) return -ENOMEM; return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata); } if (!utf8_is_valid(l)) return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l); if (*l == '[') { size_t k; char *n; k = strlen(l); assert(k > 0); if (l[k-1] != ']') { log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l); return -EBADMSG; } n = strndup(l+1, k-2); if (!n) return -ENOMEM; if (sections && !nulstr_contains(sections, n)) { if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n); free(n); *section = mfree(*section); *section_line = 0; *section_ignored = true; } else { free_and_replace(*section, n); *section_line = line; *section_ignored = false; } return 0; } if (sections && !*section) { if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored) log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring."); return 0; } e = strchr(l, '='); if (!e) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='."); return -EINVAL; } *e = 0; e++; return next_assignment(unit, filename, line, lookup, table, *section, *section_line, strstrip(l), strstrip(e), flags, userdata); }
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, uint8_t *message_type, char **error_message, dhcp_option_callback_t cb, void *userdata) { uint8_t code, len; const uint8_t *option; size_t offset = 0; while (offset < buflen) { code = options[offset ++]; switch (code) { case SD_DHCP_OPTION_PAD: continue; case SD_DHCP_OPTION_END: return 0; } if (buflen < offset + 1) return -ENOBUFS; len = options[offset ++]; if (buflen < offset + len) return -EINVAL; option = &options[offset]; switch (code) { case SD_DHCP_OPTION_MESSAGE_TYPE: if (len != 1) return -EINVAL; if (message_type) *message_type = *option; break; case SD_DHCP_OPTION_ERROR_MESSAGE: if (len == 0) return -EINVAL; if (error_message) { _cleanup_free_ char *string = NULL; /* Accept a trailing NUL byte */ if (memchr(option, 0, len - 1)) return -EINVAL; string = strndup((const char *) option, len); if (!string) return -ENOMEM; if (!ascii_is_valid(string)) return -EINVAL; free_and_replace(*error_message, string); } break; case SD_DHCP_OPTION_OVERLOAD: if (len != 1) return -EINVAL; if (overload) *overload = *option; break; default: if (cb) cb(code, len, option, userdata); break; } offset += len; } if (offset < buflen) return -EINVAL; return 0; }
int status_vprintf(const char *status, ShowStatusFlags flags, const char *format, va_list ap) { static const char status_indent[] = " "; /* "[" STATUS "] " */ _cleanup_free_ char *s = NULL; _cleanup_close_ int fd = -1; struct iovec iovec[7] = {}; int n = 0; static bool prev_ephemeral; assert(format); /* This is independent of logging, as status messages are * optional and go exclusively to the console. */ if (vasprintf(&s, format, ap) < 0) return log_oom(); /* Before you ask: yes, on purpose we open/close the console for each status line we write individually. This * is a good strategy to avoid PID 1 getting killed by the kernel's SAK concept (it doesn't fix this entirely, * but minimizes the time window the kernel might end up killing PID 1 due to SAK). It also makes things easier * for us so that we don't have to recover from hangups and suchlike triggered on the console. */ fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return fd; if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE)) { char *e; size_t emax, sl; int c; c = fd_columns(fd); if (c <= 0) c = 80; sl = status ? sizeof(status_indent)-1 : 0; emax = c - sl - 1; if (emax < 3) emax = 3; e = ellipsize(s, emax, 50); if (e) free_and_replace(s, e); } if (prev_ephemeral) iovec[n++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED "\r" ANSI_ERASE_TO_END_OF_LINE); if (status) { if (!isempty(status)) { iovec[n++] = IOVEC_MAKE_STRING("["); iovec[n++] = IOVEC_MAKE_STRING(status); iovec[n++] = IOVEC_MAKE_STRING("] "); } else iovec[n++] = IOVEC_MAKE_STRING(status_indent); } iovec[n++] = IOVEC_MAKE_STRING(s); iovec[n++] = IOVEC_MAKE_STRING("\n"); if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL)) iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE); prev_ephemeral = FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL) ; if (writev(fd, iovec, n) < 0) return -errno; return 0; }