os-util: add helpers for finding /etc/os-release

Place this new helpers in a new source file os-util.[ch], and move the
existing and related call path_is_os_tree() to it as well.
This commit is contained in:
Lennart Poettering 2018-03-26 16:32:40 +02:00
parent 080dfda85a
commit d58ad743f9
17 changed files with 193 additions and 97 deletions

View File

@ -131,6 +131,8 @@ basic_sources = files('''
ordered-set.h
pager.c
pager.h
os-util.c
os-util.h
parse-util.c
parse-util.h
path-util.c

117
src/basic/os-util.c Normal file
View File

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
#include "os-util.h"
#include "strv.h"
#include "fileio.h"
#include "string-util.h"
int path_is_os_tree(const char *path) {
int r;
assert(path);
/* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
* always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
* the case where just the os-release file is missing. */
if (laccess(path, F_OK) < 0)
return -errno;
/* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */
r = open_os_release(path, NULL, NULL);
if (r == -ENOENT) /* We got nothing */
return 0;
if (r < 0)
return r;
return 1;
}
int open_os_release(const char *root, char **ret_path, int *ret_fd) {
_cleanup_free_ char *q = NULL;
const char *p;
int k;
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL));
if (k != -ENOENT)
break;
}
if (k < 0)
return k;
if (ret_fd) {
int real_fd;
/* Convert the O_PATH fd into a proper, readable one */
real_fd = fd_reopen(k, O_RDONLY|O_CLOEXEC|O_NOCTTY);
safe_close(k);
if (real_fd < 0)
return real_fd;
*ret_fd = real_fd;
}
if (ret_path)
*ret_path = TAKE_PTR(q);
return 0;
}
int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
_cleanup_free_ char *p = NULL;
_cleanup_close_ int fd = -1;
FILE *f;
int r;
if (!ret_file)
return open_os_release(root, ret_path, NULL);
r = open_os_release(root, ret_path ? &p : NULL, &fd);
if (r < 0)
return r;
f = fdopen(fd, "re");
if (!f)
return -errno;
fd = -1;
*ret_file = f;
if (ret_path)
*ret_path = TAKE_PTR(p);
return 0;
}
int parse_os_release(const char *root, ...) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
va_list ap;
int r;
r = fopen_os_release(root, &p, &f);
if (r < 0)
return r;
va_start(ap, root);
r = parse_env_filev(f, p, NEWLINE, ap);
va_end(ap);
return r;
}
int load_os_release_pairs(const char *root, char ***ret) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
r = fopen_os_release(root, &p, &f);
if (r < 0)
return r;
return load_env_file_pairs(f, p, NEWLINE, ret);
}

12
src/basic/os-util.h Normal file
View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdio.h>
int path_is_os_tree(const char *path);
int open_os_release(const char *root, char **ret_path, int *ret_fd);
int fopen_os_release(const char *root, char **ret_path, FILE **ret_file);
int parse_os_release(const char *root, ...);
int load_os_release_pairs(const char *root, char ***ret);

View File

@ -132,32 +132,6 @@ int path_is_read_only_fs(const char *path) {
return false;
}
int path_is_os_tree(const char *path) {
int r;
assert(path);
/* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
* always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
* the case where just the os-release file is missing. */
if (laccess(path, F_OK) < 0)
return -errno;
/* We use /usr/lib/os-release as flag file if something is an OS */
r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
if (r == -ENOENT) {
/* Also check for the old location in /etc, just in case. */
r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
if (r == -ENOENT)
return 0; /* We got nothing */
}
if (r < 0)
return r;
return 1;
}
int files_same(const char *filea, const char *fileb, int flags) {
struct stat a, b;

View File

@ -35,7 +35,6 @@ int null_or_empty_path(const char *fn);
int null_or_empty_fd(int fd);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
int files_same(const char *filea, const char *fileb, int flags);

View File

@ -26,6 +26,7 @@
#include "fs-util.h"
#include "install.h"
#include "log.h"
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "selinux-access.h"

View File

@ -57,6 +57,7 @@
#include "manager.h"
#include "missing.h"
#include "mount-setup.h"
#include "os-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
@ -1215,23 +1216,18 @@ static int enforce_syscall_archs(Set *archs) {
static int status_welcome(void) {
_cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
const char *fn;
int r;
if (arg_show_status <= 0)
return 0;
FOREACH_STRING(fn, "/etc/os-release", "/usr/lib/os-release") {
r = parse_env_file(NULL, fn, NEWLINE,
"PRETTY_NAME", &pretty_name,
"ANSI_COLOR", &ansi_color,
NULL);
if (r != -ENOENT)
break;
}
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
r = parse_os_release(NULL,
"PRETTY_NAME", &pretty_name,
"ANSI_COLOR", &ansi_color,
NULL);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
if (log_get_show_color())
return status_printf(NULL, false, false,

View File

@ -33,6 +33,7 @@
#include "hostname-util.h"
#include "locale-util.h"
#include "mkdir.h"
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
@ -79,27 +80,16 @@ static bool press_any_key(void) {
static void print_welcome(void) {
_cleanup_free_ char *pretty_name = NULL;
const char *os_release = NULL;
static bool done = false;
int r;
if (done)
return;
os_release = prefix_roota(arg_root, "/etc/os-release");
r = parse_env_file(NULL, os_release, NEWLINE,
"PRETTY_NAME", &pretty_name,
NULL);
if (r == -ENOENT) {
os_release = prefix_roota(arg_root, "/usr/lib/os-release");
r = parse_env_file(NULL, os_release, NEWLINE,
"PRETTY_NAME", &pretty_name,
NULL);
}
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file: %m");
r = parse_os_release(arg_root, "PRETTY_NAME", &pretty_name, NULL);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n",
isempty(pretty_name) ? "Linux" : pretty_name);

View File

@ -16,6 +16,7 @@
#include "env-util.h"
#include "fileio-label.h"
#include "hostname-util.h"
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "selinux-util.h"
@ -98,18 +99,11 @@ static int context_read_data(Context *c) {
if (r < 0 && r != -ENOENT)
return r;
r = parse_env_file(NULL, "/etc/os-release", NEWLINE,
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
"HOME_URL", &c->data[PROP_HOME_URL],
NULL);
if (r == -ENOENT)
r = parse_env_file(NULL, "/usr/lib/os-release", NEWLINE,
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
"HOME_URL", &c->data[PROP_HOME_URL],
NULL);
r = parse_os_release(NULL,
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
"HOME_URL", &c->data[PROP_HOME_URL],
NULL);
if (r < 0 && r != -ENOENT)
return r;

View File

@ -24,6 +24,7 @@
#include "log.h"
#include "logs-show.h"
#include "microhttpd-util.h"
#include "os-util.h"
#include "parse-util.h"
#include "sigbus.h"
#include "util.h"
@ -777,10 +778,8 @@ static int request_handler_machine(
if (r < 0)
return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m");
if (parse_env_file(NULL, "/etc/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL) == -ENOENT)
(void) parse_env_file(NULL, "/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL);
get_virtualization(&v);
(void) parse_os_release(NULL, "PRETTY_NAME", &os_name, NULL);
(void) get_virtualization(&v);
r = asprintf(&json,
"{ \"machine_id\" : \"" SD_ID128_FORMAT_STR "\","

View File

@ -32,6 +32,7 @@
#include "machine-dbus.h"
#include "machine.h"
#include "mkdir.h"
#include "os-util.h"
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
@ -330,7 +331,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
switch (m->class) {
case MACHINE_HOST:
r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l);
r = load_os_release_pairs(NULL, &l);
if (r < 0)
return r;
@ -361,13 +362,10 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
if (r < 0)
_exit(EXIT_FAILURE);
fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0 && errno == ENOENT) {
fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0 && errno == ENOENT)
_exit(EXIT_NOT_FOUND);
}
if (fd < 0)
r = open_os_release(NULL, NULL, &fd);
if (r == -ENOENT)
_exit(EXIT_NOT_FOUND);
if (r < 0)
_exit(EXIT_FAILURE);
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);

View File

@ -77,6 +77,7 @@
#include "nspawn-settings.h"
#include "nspawn-setuid.h"
#include "nspawn-stub-pid1.h"
#include "os-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"

View File

@ -30,6 +30,7 @@
#include "linux-3.13/dm-ioctl.h"
#include "missing.h"
#include "mount-util.h"
#include "os-util.h"
#include "path-util.h"
#include "process-util.h"
#include "raw-clone.h"

View File

@ -35,6 +35,7 @@
#include "machine-image.h"
#include "macro.h"
#include "mkdir.h"
#include "os-util.h"
#include "path-util.h"
#include "rm-rf.h"
#include "string-table.h"
@ -923,6 +924,7 @@ int image_read_metadata(Image *i) {
sd_id128_t machine_id = SD_ID128_NULL;
_cleanup_free_ char *hostname = NULL;
_cleanup_free_ char *path = NULL;
_cleanup_fclose_ FILE *f = NULL;
r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
if (r < 0 && r != -ENOENT)
@ -962,18 +964,9 @@ int image_read_metadata(Image *i) {
log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
}
path = mfree(path);
r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
if (r == -ENOENT)
r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to chase os-release in image: %m");
else if (r >= 0) {
r = load_env_file_pairs(NULL, path, NULL, &os_release);
if (r < 0)
log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name);
}
r = load_os_release_pairs(i->path, &os_release);
if (r < 0)
log_debug_errno(r, "Failed to read os-release in image, ignoring: %m");
free_and_replace(i->hostname, hostname);
i->machine_id = machine_id;

View File

@ -242,6 +242,10 @@ tests += [
[],
[]],
[['src/test/test-os-util.c'],
[],
[]],
[['src/test/test-escape.c'],
[],
[]],

22
src/test/test-os-util.c Normal file
View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include "log.h"
#include "os-util.h"
static void test_path_is_os_tree(void) {
assert_se(path_is_os_tree("/") > 0);
assert_se(path_is_os_tree("/etc") == 0);
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
test_path_is_os_tree();
return 0;
}

View File

@ -52,12 +52,6 @@ static void test_is_symlink(void) {
unlink(name_link);
}
static void test_path_is_os_tree(void) {
assert_se(path_is_os_tree("/") > 0);
assert_se(path_is_os_tree("/etc") == 0);
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
static void test_path_is_fs_type(void) {
/* run might not be a mount point in build chroots */
if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) {
@ -81,7 +75,6 @@ static void test_path_is_temporary_fs(void) {
int main(int argc, char *argv[]) {
test_files_same();
test_is_symlink();
test_path_is_os_tree();
test_path_is_fs_type();
test_path_is_temporary_fs();