Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include "alloc-util.h"
4 : #include "env-file.h"
5 : #include "fd-util.h"
6 : #include "fs-util.h"
7 : #include "macro.h"
8 : #include "os-util.h"
9 : #include "string-util.h"
10 : #include "strv.h"
11 :
12 3 : int path_is_os_tree(const char *path) {
13 : int r;
14 :
15 3 : assert(path);
16 :
17 : /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
18 : * always results in -ENOENT, and we can properly distinguish the case where the whole root doesn't exist from
19 : * the case where just the os-release file is missing. */
20 3 : if (laccess(path, F_OK) < 0)
21 1 : return -errno;
22 :
23 : /* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */
24 2 : r = open_os_release(path, NULL, NULL);
25 2 : if (r == -ENOENT) /* We got nothing */
26 1 : return 0;
27 1 : if (r < 0)
28 0 : return r;
29 :
30 1 : return 1;
31 : }
32 :
33 2 : int open_os_release(const char *root, char **ret_path, int *ret_fd) {
34 2 : _cleanup_free_ char *q = NULL;
35 : const char *p;
36 : int k;
37 :
38 4 : FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
39 3 : k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL));
40 3 : if (k != -ENOENT)
41 1 : break;
42 : }
43 2 : if (k < 0)
44 1 : return k;
45 :
46 1 : if (ret_fd) {
47 : int real_fd;
48 :
49 : /* Convert the O_PATH fd into a proper, readable one */
50 0 : real_fd = fd_reopen(k, O_RDONLY|O_CLOEXEC|O_NOCTTY);
51 0 : safe_close(k);
52 0 : if (real_fd < 0)
53 0 : return real_fd;
54 :
55 0 : *ret_fd = real_fd;
56 : }
57 :
58 1 : if (ret_path)
59 0 : *ret_path = TAKE_PTR(q);
60 :
61 1 : return 0;
62 : }
63 :
64 0 : int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
65 0 : _cleanup_free_ char *p = NULL;
66 0 : _cleanup_close_ int fd = -1;
67 : FILE *f;
68 : int r;
69 :
70 0 : if (!ret_file)
71 0 : return open_os_release(root, ret_path, NULL);
72 :
73 0 : r = open_os_release(root, ret_path ? &p : NULL, &fd);
74 0 : if (r < 0)
75 0 : return r;
76 :
77 0 : f = fdopen(fd, "r");
78 0 : if (!f)
79 0 : return -errno;
80 0 : fd = -1;
81 :
82 0 : *ret_file = f;
83 :
84 0 : if (ret_path)
85 0 : *ret_path = TAKE_PTR(p);
86 :
87 0 : return 0;
88 : }
89 :
90 0 : int parse_os_release(const char *root, ...) {
91 0 : _cleanup_fclose_ FILE *f = NULL;
92 0 : _cleanup_free_ char *p = NULL;
93 : va_list ap;
94 : int r;
95 :
96 0 : r = fopen_os_release(root, &p, &f);
97 0 : if (r < 0)
98 0 : return r;
99 :
100 0 : va_start(ap, root);
101 0 : r = parse_env_filev(f, p, ap);
102 0 : va_end(ap);
103 :
104 0 : return r;
105 : }
106 :
107 0 : int load_os_release_pairs(const char *root, char ***ret) {
108 0 : _cleanup_fclose_ FILE *f = NULL;
109 0 : _cleanup_free_ char *p = NULL;
110 : int r;
111 :
112 0 : r = fopen_os_release(root, &p, &f);
113 0 : if (r < 0)
114 0 : return r;
115 :
116 0 : return load_env_file_pairs(f, p, ret);
117 : }
|