Branch data 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 : 12 : int path_is_os_tree(const char *path) {
13 : : int r;
14 : :
15 [ - + ]: 12 : 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 [ + + ]: 12 : if (laccess(path, F_OK) < 0)
21 : 4 : return -errno;
22 : :
23 : : /* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */
24 : 8 : r = open_os_release(path, NULL, NULL);
25 [ + + ]: 8 : if (r == -ENOENT) /* We got nothing */
26 : 4 : return 0;
27 [ - + ]: 4 : if (r < 0)
28 : 0 : return r;
29 : :
30 : 4 : return 1;
31 : : }
32 : :
33 : 8 : int open_os_release(const char *root, char **ret_path, int *ret_fd) {
34 : 8 : _cleanup_free_ char *q = NULL;
35 : : const char *p;
36 : : int k;
37 : :
38 [ + + ]: 16 : FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
39 [ - + - + ]: 12 : k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL));
40 [ + + ]: 12 : if (k != -ENOENT)
41 : 4 : break;
42 : : }
43 [ + + ]: 8 : if (k < 0)
44 : 4 : return k;
45 : :
46 [ - + ]: 4 : 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 [ - + ]: 4 : if (ret_path)
59 : 0 : *ret_path = TAKE_PTR(q);
60 : :
61 : 4 : 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 : : }
|