]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/open-file.c
hwdb: Add mapping for Xiaomi Mipad 2 bottom bezel capacitive buttons
[thirdparty/systemd.git] / src / shared / open-file.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4
5 #include "escape.h"
6 #include "extract-word.h"
7 #include "fd-util.h"
8 #include "open-file.h"
9 #include "path-util.h"
10 #include "string-table.h"
11 #include "string-util.h"
12
13 int open_file_parse(const char *v, OpenFile **ret) {
14 _cleanup_free_ char *options = NULL;
15 _cleanup_(open_file_freep) OpenFile *of = NULL;
16 int r;
17
18 assert(v);
19 assert(ret);
20
21 of = new0(OpenFile, 1);
22 if (!of)
23 return -ENOMEM;
24
25 r = extract_many_words(&v, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_CUNESCAPE, &of->path, &of->fdname, &options);
26 if (r < 0)
27 return r;
28 if (r == 0)
29 return -EINVAL;
30
31 /* Enforce that at most 3 colon-separated words are present */
32 if (!isempty(v))
33 return -EINVAL;
34
35 for (const char *p = options;;) {
36 OpenFileFlag flag;
37 _cleanup_free_ char *word = NULL;
38
39 r = extract_first_word(&p, &word, ",", 0);
40 if (r < 0)
41 return r;
42 if (r == 0)
43 break;
44
45 flag = open_file_flags_from_string(word);
46 if (flag < 0)
47 return flag;
48
49 if ((flag & of->flags) != 0)
50 return -EINVAL;
51
52 of->flags |= flag;
53 }
54
55 if (isempty(of->fdname)) {
56 of->fdname = mfree(of->fdname);
57 r = path_extract_filename(of->path, &of->fdname);
58 if (r < 0)
59 return r;
60 }
61
62 r = open_file_validate(of);
63 if (r < 0)
64 return r;
65
66 *ret = TAKE_PTR(of);
67
68 return 0;
69 }
70
71 int open_file_validate(const OpenFile *of) {
72 assert(of);
73
74 if (!path_is_valid(of->path) || !path_is_absolute(of->path))
75 return -EINVAL;
76
77 if (!fdname_is_valid(of->fdname))
78 return -EINVAL;
79
80 if ((FLAGS_SET(of->flags, OPENFILE_READ_ONLY) + FLAGS_SET(of->flags, OPENFILE_APPEND) +
81 FLAGS_SET(of->flags, OPENFILE_TRUNCATE)) > 1)
82 return -EINVAL;
83
84 if ((of->flags & ~_OPENFILE_MASK_PUBLIC) != 0)
85 return -EINVAL;
86
87 return 0;
88 }
89
90 int open_file_to_string(const OpenFile *of, char **ret) {
91 _cleanup_free_ char *options = NULL, *fname = NULL, *s = NULL;
92 bool has_fdname = false;
93 int r;
94
95 assert(of);
96 assert(ret);
97
98 s = xescape(of->path, ":");
99 if (!s)
100 return -ENOMEM;
101
102 r = path_extract_filename(of->path, &fname);
103 if (r < 0)
104 return r;
105
106 has_fdname = !streq(fname, of->fdname);
107 if (has_fdname)
108 if (!strextend(&s, ":", of->fdname))
109 return -ENOMEM;
110
111 for (OpenFileFlag flag = OPENFILE_READ_ONLY; flag < _OPENFILE_MAX; flag <<= 1)
112 if (FLAGS_SET(of->flags, flag) && !strextend_with_separator(&options, ",", open_file_flags_to_string(flag)))
113 return -ENOMEM;
114
115 if (options)
116 if (!(has_fdname ? strextend(&s, ":", options) : strextend(&s, "::", options)))
117 return -ENOMEM;
118
119 *ret = TAKE_PTR(s);
120
121 return 0;
122 }
123
124 OpenFile* open_file_free(OpenFile *of) {
125 if (!of)
126 return NULL;
127
128 free(of->path);
129 free(of->fdname);
130
131 return mfree(of);
132 }
133
134 static const char * const open_file_flags_table[_OPENFILE_MAX] = {
135 [OPENFILE_READ_ONLY] = "read-only",
136 [OPENFILE_APPEND] = "append",
137 [OPENFILE_TRUNCATE] = "truncate",
138 [OPENFILE_GRACEFUL] = "graceful",
139 };
140
141 DEFINE_STRING_TABLE_LOOKUP(open_file_flags, OpenFileFlag);