load-fragment.c revision 47be870bd83fb3719dffc3ee9348a409ab762a14
/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include "unit.h"
#include "strv.h"
#include "conf-parser.h"
#include "load-fragment.h"
#include "log.h"
#include "ioprio.h"
#include "securebits.h"
#include "missing.h"
static int config_parse_deps(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
char *w;
size_t l;
char *state;
char *t;
int r;
if (!(t = strndup(w, l)))
return -ENOMEM;
r = unit_add_dependency_by_name(u, d, t);
free(t);
if (r < 0)
return r;
}
return 0;
}
static int config_parse_names(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
char *w;
size_t l;
char *state;
char *t;
int r;
if (!(t = strndup(w, l)))
return -ENOMEM;
if (other) {
if (other != u) {
free(t);
return -EEXIST;
}
if ((r = unit_merge(u, other)) < 0) {
free(t);
return r;
}
}
} else {
if ((r = unit_add_name(u, t)) < 0) {
free(t);
return r;
}
}
free(t);
}
return 0;
}
static int config_parse_listen(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
int r;
SocketPort *p;
Socket *s;
return -ENOMEM;
p->type = SOCKET_FIFO;
free(p);
return -ENOMEM;
}
} else {
p->type = SOCKET_SOCKET;
free(p);
return r;
}
else {
}
free(p);
return -EPROTONOSUPPORT;
}
}
p->fd = -1;
return 0;
}
static int config_parse_socket_bind(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
int r;
Socket *s;
if ((r = parse_boolean(rvalue)) < 0) {
return r;
}
return 0;
}
static int config_parse_nice(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int priority, r;
return r;
}
return -ERANGE;
}
c->nice_set = false;
return 0;
}
static int config_parse_oom_adjust(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int oa, r;
return r;
}
return -ERANGE;
}
c->oom_adjust = oa;
c->oom_adjust_set = true;
return 0;
}
static int config_parse_umask(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
long l;
char *x = NULL;
errno = 0;
if (!x || *x || errno) {
}
if (l < 0000 || l > 0777) {
return -ERANGE;
}
*m = (mode_t) l;
return 0;
}
static int config_parse_exec(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
char **n;
char *w;
unsigned k;
size_t l;
char *state;
k = 0;
k++;
if (!(n = new(char*, k+1)))
return -ENOMEM;
k = 0;
if (!(n[k++] = strndup(w, l)))
goto fail;
n[k] = NULL;
if (!n[0] || !path_is_absolute(n[0])) {
strv_free(n);
return -EINVAL;
}
goto fail;
goto fail;
if (*e) {
/* It's kinda important that we keep the order here */
} else
*e = nce;
return 0;
fail:
for (; k > 0; k--)
free(n[k-1]);
free(n);
return -ENOMEM;
}
static int config_parse_usec(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
unsigned long long u;
int r;
if ((r = safe_atollu(rvalue, &u)) < 0) {
return r;
}
/* We actually assume the user configures seconds. Later on we
* might choose to support suffixes for time values, to
* configure bigger or smaller units */
*usec = u * USEC_PER_SEC;
return 0;
}
static int config_parse_service_type(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ServiceType x;
if ((x = service_type_from_string(rvalue)) < 0) {
return -EBADMSG;
}
s->type = x;
return 0;
}
static int config_parse_service_restart(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
if ((x = service_restart_from_string(rvalue)) < 0) {
return -EBADMSG;
}
s->restart = x;
return 0;
}
static int config_parse_bindtodevice(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
char *n;
return -ENOMEM;
} else
n = NULL;
free(s->bind_to_device);
s->bind_to_device = n;
return 0;
}
static int config_parse_output(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecOutput *o = data, x;
if ((x = exec_output_from_string(rvalue)) < 0) {
return -EBADMSG;
}
*o = x;
return 0;
}
static int config_parse_input(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
if ((x = exec_input_from_string(rvalue)) < 0) {
return -EBADMSG;
}
*i = x;
return 0;
}
static int config_parse_facility(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
int *o = data, x;
if ((x = log_facility_from_string(rvalue)) < 0)
/* Second try, let's see if this is a number. */
return -EBADMSG;
}
*o = LOG_MAKEPRI(x, LOG_PRI(*o));
return 0;
}
static int config_parse_level(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
int *o = data, x;
if ((x = log_level_from_string(rvalue)) < 0)
/* Second try, let's see if this is a number. */
return -EBADMSG;
}
*o = LOG_MAKEPRI(LOG_FAC(*o), x);
return 0;
}
static int config_parse_io_class(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int x;
if ((x = ioprio_class_from_string(rvalue)) < 0)
/* Second try, let's see if this is a number. */
return -EBADMSG;
}
c->ioprio_set = true;
return 0;
}
static int config_parse_io_priority(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int i;
return -EBADMSG;
}
c->ioprio_set = true;
return 0;
}
static int config_parse_cpu_sched_policy(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int x;
if ((x = sched_policy_from_string(rvalue)) < 0)
/* Second try, let's see if this is a number. */
return -EBADMSG;
}
c->cpu_sched_policy = x;
c->cpu_sched_set = true;
return 0;
}
static int config_parse_cpu_sched_prio(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int i;
if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
return -EBADMSG;
}
c->cpu_sched_priority = i;
c->cpu_sched_set = true;
return 0;
}
static int config_parse_cpu_affinity(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
char *w;
size_t l;
char *state;
char *t;
int r;
unsigned cpu;
if (!(t = strndup(w, l)))
return -ENOMEM;
free(t);
if (r < 0 || cpu >= CPU_SETSIZE) {
return -EBADMSG;
}
}
c->cpu_affinity_set = true;
return 0;
}
static int config_parse_capabilities(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
return -ENOMEM;
return -EBADMSG;
}
if (c->capabilities)
cap_free(c->capabilities);
c->capabilities = cap;
return 0;
}
static int config_parse_secure_bits(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
char *w;
size_t l;
char *state;
if (first_word(w, "keep-caps"))
c->secure_bits |= SECURE_KEEP_CAPS;
else if (first_word(w, "keep-caps-locked"))
else if (first_word(w, "no-setuid-fixup"))
else if (first_word(w, "no-setuid-fixup-locked"))
else if (first_word(w, "noroot"))
c->secure_bits |= SECURE_NOROOT;
else if (first_word(w, "noroot-locked"))
c->secure_bits |= SECURE_NOROOT_LOCKED;
else {
return -EBADMSG;
}
}
return 0;
}
static int config_parse_bounding_set(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
char *w;
size_t l;
char *state;
char *t;
int r;
if (!(t = strndup(w, l)))
return -ENOMEM;
r = cap_from_name(t, &cap);
free(t);
if (r < 0) {
return -EBADMSG;
}
}
return 0;
}
static int config_parse_timer_slack_ns(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
unsigned long u;
int r;
if ((r = safe_atolu(rvalue, &u)) < 0) {
return r;
}
c->timer_slack_ns = u;
return 0;
}
static int config_parse_limit(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
unsigned long long u;
int r;
if ((r = safe_atollu(rvalue, &u)) < 0) {
return r;
}
if (!*rl)
return -ENOMEM;
return 0;
}
#define FOLLOW_MAX 8
unsigned c = 0;
int fd, r;
FILE *f;
/* This will update the filename pointer if the loaded file is
* reached by a symlink. The old string will be freed. */
for (;;) {
if (c++ >= FOLLOW_MAX)
return -ELOOP;
/* Add the file name we are currently looking at to
* the names of this unit */
return -ENOMEM;
return r;
}
}
/* Try to open the file name, but don't if its a symlink */
break;
return -errno;
/* Hmm, so this is a symlink. Let's read the name, and follow it manually */
return r;
if (!k)
return -ENOMEM;
*filename = k;
}
r = -errno;
return r;
}
*_f = f;
return 0;
}
static const char* const section_table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "Service",
[UNIT_TIMER] = "Timer",
[UNIT_SOCKET] = "Socket",
[UNIT_TARGET] = "Target",
[UNIT_DEVICE] = "Device",
[UNIT_MOUNT] = "Mount",
[UNIT_AUTOMOUNT] = "Automount",
[UNIT_SNAPSHOT] = "Snapshot"
};
const ConfigItem items[] = {
};
const char *sections[3];
char *k;
int r;
FILE *f;
sections[0] = "Meta";
return -ENOMEM;
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit
* name set while doing so */
r = -ENOMEM;
goto finish;
}
if (r == -ENOENT)
r = 0; /* returning 0 means: no suitable config file found */
goto finish;
}
/* Now, parse the file contents */
if (r < 0)
goto finish;
/* Let's try to add in all symlink names we found */
while ((k = set_steal_first(symlink_names))) {
if ((r = unit_add_name(u, k)) < 0)
goto finish;
if (id == k)
unit_choose_id(u, id);
free(k);
}
r = 1; /* returning 1 means: suitable config file found and loaded */
while ((k = set_steal_first(symlink_names)))
free(k);
return r;
}
int unit_load_fragment(Unit *u) {
int r = 0;
ExecContext *c;
assert(u);
else {
Iterator i;
char *t;
/* Try to find a name we can load this with */
if ((r = load_from_path(u, t)) != 0)
return r;
}
c = &u->socket.exec_context;
c = &u->service.exec_context;
else
c = NULL;
if (r >= 0 && c &&
int k;
/* If syslog or kernel logging is requested, make sure
* our own logging daemon is run first. */
return k;
return k;
}
return r;
}