]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/fileio.c
Always use errno > 0 to help gcc
[thirdparty/systemd.git] / src / shared / fileio.c
CommitLineData
a5c32cff
HH
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include "fileio.h"
24#include "util.h"
25#include "strv.h"
26
27int write_one_line_file(const char *fn, const char *line) {
28 _cleanup_fclose_ FILE *f = NULL;
29
30 assert(fn);
31 assert(line);
32
33 f = fopen(fn, "we");
34 if (!f)
35 return -errno;
36
37 errno = 0;
38 if (fputs(line, f) < 0)
39 return errno ? -errno : -EIO;
40
41 if (!endswith(line, "\n"))
42 fputc('\n', f);
43
44 fflush(f);
45
46 if (ferror(f))
47 return errno ? -errno : -EIO;
48
49 return 0;
50}
51
52int write_one_line_file_atomic(const char *fn, const char *line) {
53 _cleanup_fclose_ FILE *f = NULL;
54 _cleanup_free_ char *p = NULL;
55 int r;
56
57 assert(fn);
58 assert(line);
59
60 r = fopen_temporary(fn, &f, &p);
61 if (r < 0)
62 return r;
63
64 fchmod_umask(fileno(f), 0644);
65
66 errno = 0;
67 if (fputs(line, f) < 0) {
68 r = -errno;
69 goto finish;
70 }
71
72 if (!endswith(line, "\n"))
73 fputc('\n', f);
74
75 fflush(f);
76
77 if (ferror(f))
78 r = errno ? -errno : -EIO;
79 else {
80 if (rename(p, fn) < 0)
81 r = -errno;
82 else
83 r = 0;
84 }
85
86finish:
87 if (r < 0)
88 unlink(p);
89
90 return r;
91}
92
93int read_one_line_file(const char *fn, char **line) {
94 _cleanup_fclose_ FILE *f = NULL;
95 char t[LINE_MAX], *c;
96
97 assert(fn);
98 assert(line);
99
100 f = fopen(fn, "re");
101 if (!f)
102 return -errno;
103
104 if (!fgets(t, sizeof(t), f)) {
105
106 if (ferror(f))
107 return errno ? -errno : -EIO;
108
109 t[0] = 0;
110 }
111
112 c = strdup(t);
113 if (!c)
114 return -ENOMEM;
115 truncate_nl(c);
116
117 *line = c;
118 return 0;
119}
120
121int read_full_file(const char *fn, char **contents, size_t *size) {
122 _cleanup_fclose_ FILE *f = NULL;
123 size_t n, l;
124 _cleanup_free_ char *buf = NULL;
125 struct stat st;
126
127 assert(fn);
128 assert(contents);
129
130 f = fopen(fn, "re");
131 if (!f)
132 return -errno;
133
134 if (fstat(fileno(f), &st) < 0)
135 return -errno;
136
137 /* Safety check */
138 if (st.st_size > 4*1024*1024)
139 return -E2BIG;
140
141 n = st.st_size > 0 ? st.st_size : LINE_MAX;
142 l = 0;
143
144 for (;;) {
145 char *t;
146 size_t k;
147
148 t = realloc(buf, n+1);
149 if (!t)
150 return -ENOMEM;
151
152 buf = t;
153 k = fread(buf + l, 1, n - l, f);
154
155 if (k <= 0) {
156 if (ferror(f))
157 return -errno;
158
159 break;
160 }
161
162 l += k;
163 n *= 2;
164
165 /* Safety check */
166 if (n > 4*1024*1024)
167 return -E2BIG;
168 }
169
170 buf[l] = 0;
171 *contents = buf;
172 buf = NULL;
173
174 if (size)
175 *size = l;
176
177 return 0;
178}
179
180int parse_env_file(
181 const char *fname,
182 const char *separator, ...) {
183
184 int r = 0;
185 char *contents = NULL, *p;
186
187 assert(fname);
188 assert(separator);
189
1c17cbed
ZJS
190 r = read_full_file(fname, &contents, NULL);
191 if (r < 0)
a5c32cff
HH
192 return r;
193
194 p = contents;
195 for (;;) {
196 const char *key = NULL;
197
198 p += strspn(p, separator);
199 p += strspn(p, WHITESPACE);
200
201 if (!*p)
202 break;
203
204 if (!strchr(COMMENTS, *p)) {
205 va_list ap;
206 char **value;
207
208 va_start(ap, separator);
209 while ((key = va_arg(ap, char *))) {
210 size_t n;
211 char *v;
212
213 value = va_arg(ap, char **);
214
215 n = strlen(key);
216 if (!strneq(p, key, n) ||
217 p[n] != '=')
218 continue;
219
220 p += n + 1;
221 n = strcspn(p, separator);
222
223 if (n >= 2 &&
224 strchr(QUOTES, p[0]) &&
225 p[n-1] == p[0])
226 v = strndup(p+1, n-2);
227 else
228 v = strndup(p, n);
229
230 if (!v) {
231 r = -ENOMEM;
232 va_end(ap);
233 goto fail;
234 }
235
236 if (v[0] == '\0') {
237 /* return empty value strings as NULL */
238 free(v);
239 v = NULL;
240 }
241
242 free(*value);
243 *value = v;
244
245 p += n;
246
247 r ++;
248 break;
249 }
250 va_end(ap);
251 }
252
253 if (!key)
254 p += strcspn(p, separator);
255 }
256
257fail:
258 free(contents);
259 return r;
260}
261
262int load_env_file(const char *fname, char ***rl) {
263
264 _cleanup_fclose_ FILE *f;
265 _cleanup_strv_free_ char **m = NULL;
266 _cleanup_free_ char *c = NULL;
267
268 assert(fname);
269 assert(rl);
270
271 /* This reads an environment file, but will not complain about
272 * any invalid assignments, that needs to be done by the
273 * caller */
274
275 f = fopen(fname, "re");
276 if (!f)
277 return -errno;
278
279 while (!feof(f)) {
280 char l[LINE_MAX], *p, *cs, *b;
281
282 if (!fgets(l, sizeof(l), f)) {
283 if (ferror(f))
284 return -errno;
285
286 /* The previous line was a continuation line?
287 * Let's process it now, before we leave the
288 * loop */
289 if (c)
290 goto process;
291
292 break;
293 }
294
295 /* Is this a continuation line? If so, just append
296 * this to c, and go to next line right-away */
297 cs = endswith(l, "\\\n");
298 if (cs) {
299 *cs = '\0';
300 b = strappend(c, l);
301 if (!b)
302 return -ENOMEM;
303
304 free(c);
305 c = b;
306 continue;
307 }
308
309 /* If the previous line was a continuation line,
310 * append the current line to it */
311 if (c) {
312 b = strappend(c, l);
313 if (!b)
314 return -ENOMEM;
315
316 free(c);
317 c = b;
318 }
319
320 process:
321 p = strstrip(c ? c : l);
322
323 if (*p && !strchr(COMMENTS, *p)) {
324 _cleanup_free_ char *u;
325 int k;
326
327 u = normalize_env_assignment(p);
328 if (!u)
329 return -ENOMEM;
330
331 k = strv_extend(&m, u);
332 if (k < 0)
333 return -ENOMEM;
334 }
335
336 free(c);
337 c = NULL;
338 }
339
340 *rl = m;
341 m = NULL;
342
343 return 0;
344}
345
346int write_env_file(const char *fname, char **l) {
1c17cbed
ZJS
347 char **i;
348 char _cleanup_free_ *p = NULL;
349 FILE _cleanup_fclose_ *f = NULL;
a5c32cff
HH
350 int r;
351
352 r = fopen_temporary(fname, &f, &p);
353 if (r < 0)
354 return r;
355
356 fchmod_umask(fileno(f), 0644);
357
358 errno = 0;
359 STRV_FOREACH(i, l) {
360 fputs(*i, f);
361 fputc('\n', f);
362 }
363
364 fflush(f);
365
366 if (ferror(f)) {
8333c77e 367 if (errno > 0)
a5c32cff
HH
368 r = -errno;
369 else
370 r = -EIO;
371 } else {
372 if (rename(p, fname) < 0)
373 r = -errno;
374 else
375 r = 0;
376 }
377
378 if (r < 0)
379 unlink(p);
380
a5c32cff
HH
381 return r;
382}