]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/parse-helpers.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / shared / parse-helpers.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "af-list.h"
4 #include "extract-word.h"
5 #include "ip-protocol-list.h"
6 #include "log.h"
7 #include "parse-helpers.h"
8 #include "parse-util.h"
9 #include "path-util.h"
10 #include "utf8.h"
11
12 int path_simplify_and_warn(
13 char *path,
14 unsigned flag,
15 const char *unit,
16 const char *filename,
17 unsigned line,
18 const char *lvalue) {
19
20 bool fatal = flag & PATH_CHECK_FATAL;
21
22 assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
23
24 if (!utf8_is_valid(path))
25 return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
26
27 if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
28 bool absolute;
29
30 absolute = path_is_absolute(path);
31
32 if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
33 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
34 "%s= path is not absolute%s: %s",
35 lvalue, fatal ? "" : ", ignoring", path);
36
37 if (absolute && (flag & PATH_CHECK_RELATIVE))
38 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
39 "%s= path is absolute%s: %s",
40 lvalue, fatal ? "" : ", ignoring", path);
41 }
42
43 path_simplify(path);
44
45 if (!path_is_valid(path))
46 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
47 "%s= path has invalid length (%zu bytes)%s.",
48 lvalue, strlen(path), fatal ? "" : ", ignoring");
49
50 if (!path_is_normalized(path))
51 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
52 "%s= path is not normalized%s: %s",
53 lvalue, fatal ? "" : ", ignoring", path);
54
55 return 0;
56 }
57
58 static int parse_af_token(
59 const char *token,
60 int *family,
61 int *ip_protocol,
62 uint16_t *nr_ports,
63 uint16_t *port_min) {
64
65 int af;
66
67 assert(token);
68 assert(family);
69
70 af = af_from_ipv4_ipv6(token);
71 if (af == AF_UNSPEC)
72 return -EINVAL;
73
74 *family = af;
75 return 0;
76 }
77
78 static int parse_ip_protocol_token(
79 const char *token,
80 int *family,
81 int *ip_protocol,
82 uint16_t *nr_ports,
83 uint16_t *port_min) {
84
85 int proto;
86
87 assert(token);
88 assert(ip_protocol);
89
90 proto = ip_protocol_from_tcp_udp(token);
91 if (proto < 0)
92 return -EINVAL;
93
94 *ip_protocol = proto;
95 return 0;
96 }
97
98 static int parse_ip_ports_token(
99 const char *token,
100 int *family,
101 int *ip_protocol,
102 uint16_t *nr_ports,
103 uint16_t *port_min) {
104
105 assert(token);
106 assert(nr_ports);
107 assert(port_min);
108
109 if (streq(token, "any"))
110 *nr_ports = *port_min = 0;
111 else {
112 uint16_t mn = 0, mx = 0;
113 int r = parse_ip_port_range(token, &mn, &mx);
114 if (r < 0)
115 return r;
116
117 *nr_ports = mx - mn + 1;
118 *port_min = mn;
119 }
120
121 return 0;
122 }
123
124 typedef int (*parse_token_f)(
125 const char *,
126 int *,
127 int *,
128 uint16_t *,
129 uint16_t *);
130
131 int parse_socket_bind_item(
132 const char *str,
133 int *address_family,
134 int *ip_protocol,
135 uint16_t *nr_ports,
136 uint16_t *port_min) {
137
138 /* Order of token parsers is important. */
139 const parse_token_f parsers[] = {
140 &parse_af_token,
141 &parse_ip_protocol_token,
142 &parse_ip_ports_token,
143 };
144 parse_token_f const *parser_ptr = parsers;
145 int af = AF_UNSPEC, proto = 0, r;
146 uint16_t nr = 0, mn = 0;
147 const char *p = ASSERT_PTR(str);
148
149 assert(address_family);
150 assert(ip_protocol);
151 assert(nr_ports);
152 assert(port_min);
153
154 if (isempty(p))
155 return -EINVAL;
156
157 for (;;) {
158 _cleanup_free_ char *token = NULL;
159
160 r = extract_first_word(&p, &token, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
161 if (r == 0)
162 break;
163 if (r < 0)
164 return r;
165
166 if (isempty(token))
167 return -EINVAL;
168
169 while (parser_ptr != parsers + ELEMENTSOF(parsers)) {
170 r = (*parser_ptr)(token, &af, &proto, &nr, &mn);
171 if (r == -ENOMEM)
172 return r;
173
174 ++parser_ptr;
175 /* Continue to next token if parsing succeeded,
176 * otherwise apply next parser to the same token.
177 */
178 if (r >= 0)
179 break;
180 }
181 if (parser_ptr == parsers + ELEMENTSOF(parsers))
182 break;
183 }
184
185 /* Failed to parse a token. */
186 if (r < 0)
187 return r;
188
189 /* Parsers applied successfully, but end of the string not reached. */
190 if (p)
191 return -EINVAL;
192
193 *address_family = af;
194 *ip_protocol = proto;
195 *nr_ports = nr;
196 *port_min = mn;
197 return 0;
198 }