fileio.c revision e93c33d4aadb41427f215d43545e7fadc6bcec6f
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <unistd.h>
#include <sys/sendfile.h>
#include "fileio.h"
#include "util.h"
#include "strv.h"
#include "utf8.h"
#include "ctype.h"
errno = 0;
fputc('\n', f);
fflush(f);
if (ferror(f))
return 0;
}
if (!f)
return -errno;
return write_string_to_file(f, line);
}
_cleanup_free_ char *p = NULL;
int r;
r = fopen_temporary(fn, &f, &p);
if (r < 0)
return r;
errno = 0;
fputc('\n', f);
fflush(f);
if (ferror(f))
else {
r = -errno;
else
r = 0;
}
if (r < 0)
unlink(p);
return r;
}
char t[LINE_MAX], *c;
if (!f)
return -errno;
if (!fgets(t, sizeof(t), f)) {
if (ferror(f))
t[0] = 0;
}
c = strdup(t);
if (!c)
return -ENOMEM;
truncate_nl(c);
*line = c;
return 0;
}
_cleanup_fclose_ FILE *f;
int r;
ssize_t s;
size_t n, l;
if (!f)
return -errno;
if (r < 0)
return -errno;
if (s < 0)
/* continue below */
} else
return -errno;
else
return s;
/* Safety check */
return -E2BIG;
l = 0;
while (true) {
char *t;
size_t k;
if (!t)
return -ENOMEM;
buf = t;
if (k <= 0) {
if (ferror(f))
return -errno;
break;
}
l += k;
n *= 2;
/* Safety check */
if (n > 4*1024*1024)
return -E2BIG;
}
if (r < 0)
return -errno;
return (ssize_t) l;
}
size_t n, l;
if (!f)
return -errno;
return -errno;
/* Safety check */
return -E2BIG;
l = 0;
for (;;) {
char *t;
size_t k;
if (!t)
return -ENOMEM;
buf = t;
if (k <= 0) {
if (ferror(f))
return -errno;
break;
}
l += k;
n *= 2;
/* Safety check */
if (n > 4*1024*1024)
return -E2BIG;
}
buf[l] = 0;
if (size)
*size = l;
return 0;
}
static int parse_env_file_internal(
const char *fname,
const char *newline,
void *userdata) {
size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
int r;
unsigned line = 1;
enum {
KEY,
if (r < 0)
return r;
for (p = contents; *p; p++) {
char c = *p;
switch (state) {
case PRE_KEY:
else if (!strchr(WHITESPACE, c)) {
r = -ENOMEM;
goto fail;
}
}
break;
case KEY:
line ++;
n_key = 0;
} else if (c == '=') {
} else {
if (!strchr(WHITESPACE, c))
r = -ENOMEM;
goto fail;
}
}
break;
case PRE_VALUE:
line ++;
if (value)
/* strip trailing whitespace from key */
key[last_key_whitespace] = 0;
if (r < 0)
goto fail;
n_key = 0;
value_alloc = n_value = 0;
} else if (c == '\'')
else if (c == '\"')
else if (c == '\\')
else if (!strchr(WHITESPACE, c)) {
r = -ENOMEM;
goto fail;
}
}
break;
case VALUE:
line ++;
if (value)
/* Chomp off trailing whitespace from value */
value[last_value_whitespace] = 0;
/* strip trailing whitespace from key */
key[last_key_whitespace] = 0;
if (r < 0)
goto fail;
n_key = 0;
value_alloc = n_value = 0;
} else if (c == '\\') {
} else {
if (!strchr(WHITESPACE, c))
r = -ENOMEM;
goto fail;
}
}
break;
case VALUE_ESCAPE:
/* Escaped newlines we eat up entirely */
r = -ENOMEM;
goto fail;
}
}
break;
case SINGLE_QUOTE_VALUE:
if (c == '\'')
else if (c == '\\')
else {
r = -ENOMEM;
goto fail;
}
}
break;
r = -ENOMEM;
goto fail;
}
}
break;
case DOUBLE_QUOTE_VALUE:
if (c == '\"')
else if (c == '\\')
else {
r = -ENOMEM;
goto fail;
}
}
break;
r = -ENOMEM;
goto fail;
}
}
break;
case COMMENT:
if (c == '\\')
line ++;
}
break;
case COMMENT_ESCAPE:
break;
}
}
state == VALUE_ESCAPE ||
state == SINGLE_QUOTE_VALUE ||
state == DOUBLE_QUOTE_VALUE ||
if (value)
value[last_value_whitespace] = 0;
/* strip trailing whitespace from key */
key[last_key_whitespace] = 0;
if (r < 0)
goto fail;
}
return 0;
fail:
return r;
}
/* FIXME: filter UTF-8 */
log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.",
else {
const char *k;
char **v;
free(*v);
*v = value;
return 1;
}
}
}
return 0;
}
int parse_env_file(
const char *fname,
const char *newline, ...) {
int r;
if (!newline)
return r;
}
/* FIXME: filter UTF-8 */
log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.",
else {
char ***m = userdata;
char *p;
int r;
if (!p)
return -ENOMEM;
r = strv_push(m, p);
if (r < 0) {
free(p);
return r;
}
}
return 0;
}
char **m = NULL;
int r;
if (!newline)
if (r < 0) {
strv_free(m);
return r;
}
*rl = m;
return 0;
}
static void write_env_var(FILE *f, const char *v) {
const char *p;
p = strchr(v, '=');
if (!p) {
/* Fallback */
fputs(v, f);
fputc('\n', f);
return;
}
p++;
fwrite(v, 1, p-v, f);
fputc('\"', f);
for (; *p; p++) {
if (strchr("\'\"\\`$", *p))
fputc('\\', f);
fputc(*p, f);
}
fputc('\"', f);
} else
fputs(p, f);
fputc('\n', f);
}
int write_env_file(const char *fname, char **l) {
char **i;
_cleanup_free_ char *p = NULL;
int r;
r = fopen_temporary(fname, &f, &p);
if (r < 0)
return r;
errno = 0;
STRV_FOREACH(i, l)
write_env_var(f, *i);
fflush(f);
if (ferror(f))
else {
r = -errno;
else
r = 0;
}
if (r < 0)
unlink(p);
return r;
}
int r;
int len;
char *ans;
if (r < 0)
return r;
return 0;
if (len == 0)
return 0;
if (!ans)
return -ENOMEM;
*interpreter = ans;
return 1;
}
/**
* should start with '\n' and end with a ':'. Whitespace and zeros
* after the ':' will be skipped. field must be freed afterwards.
*/
char *t;
int r;
if (r < 0)
return r;
if (!t)
return -ENOENT;
if (*t) {
t += strspn(t, " \t");
/* Also skip zeros, because when this is used for
* capabilities, we don't want the zeros. This way the
* same capability set always maps to the same string,
* irrespective of the total capability set size. For
* other numbers it shouldn't matter. */
t += strspn(t, "0");
/* Back off one char if there's nothing but whitespace
and zeros */
if (!*t || isspace(*t))
t --;
}
if (!*field)
return -ENOMEM;
return 0;
}