unit: split unit_printf() and friends into its own .c file

This commit is contained in:
Lennart Poettering 2012-09-18 11:27:56 +02:00
parent 9900625116
commit 41f9172f42
9 changed files with 325 additions and 261 deletions

View File

@ -909,6 +909,8 @@ noinst_LTLIBRARIES += \
libsystemd_core_la_SOURCES = \ libsystemd_core_la_SOURCES = \
src/core/unit.c \ src/core/unit.c \
src/core/unit.h \ src/core/unit.h \
src/core/unit-printf.c \
src/core/unit-printf.h \
src/core/job.c \ src/core/job.c \
src/core/job.h \ src/core/job.h \
src/core/manager.c \ src/core/manager.c \

7
TODO
View File

@ -30,7 +30,8 @@ F18:
Features: Features:
* instantiated target units * instantiated [Install] for target units
https://bugs.freedesktop.org/show_bug.cgi?id=54377
* support *static* (/run) hibernate inhibitors. All rpm -i actions should completely prevent any * support *static* (/run) hibernate inhibitors. All rpm -i actions should completely prevent any
sort of hibernate action until the next reboot. If the kernel or any other base tool is replaced sort of hibernate action until the next reboot. If the kernel or any other base tool is replaced
@ -40,10 +41,12 @@ Features:
* move debug shell to tty6 and make sure this doesn't break the gettys on tty6 * move debug shell to tty6 and make sure this doesn't break the gettys on tty6
* move cryptsetup key caching into kernel keyctl? * move cryptsetup key caching into kernel keyctl?
https://bugs.freedesktop.org/show_bug.cgi?id=54982
* make nspawn work without terminal * make nspawn work without terminal
* hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it * hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it
https://bugs.freedesktop.org/show_bug.cgi?id=54712
* after deserializing sockets in socket.c we should reapply sockopts and things * after deserializing sockets in socket.c we should reapply sockopts and things
@ -55,8 +58,6 @@ Features:
* http://lists.freedesktop.org/archives/systemd-devel/2012-September/006502.html * http://lists.freedesktop.org/archives/systemd-devel/2012-September/006502.html
* don't use writev() in tmpfiles for sake of compat with sysfs?
* come up with a nice way to write queue/read_ahead_kb for a block device without interfering with readahead * come up with a nice way to write queue/read_ahead_kb for a block device without interfering with readahead
* journald: add kernel cmdline option to disable ratelimiting for debug purposes * journald: add kernel cmdline option to disable ratelimiting for debug purposes

View File

@ -42,6 +42,7 @@
#include "securebits.h" #include "securebits.h"
#include "missing.h" #include "missing.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h"
#include "bus-errors.h" #include "bus-errors.h"
#include "utf8.h" #include "utf8.h"
#include "path-util.h" #include "path-util.h"

View File

@ -33,6 +33,7 @@
#include "log.h" #include "log.h"
#include "strv.h" #include "strv.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h"
#include "dbus-service.h" #include "dbus-service.h"
#include "special.h" #include "special.h"
#include "bus-errors.h" #include "bus-errors.h"

View File

@ -39,6 +39,7 @@
#include "mkdir.h" #include "mkdir.h"
#include "path-util.h" #include "path-util.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h"
#include "dbus-socket.h" #include "dbus-socket.h"
#include "missing.h" #include "missing.h"
#include "special.h" #include "special.h"

282
src/core/unit-printf.c Normal file
View File

@ -0,0 +1,282 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
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 "systemd/sd-id128.h"
#include "unit.h"
#include "specifier.h"
#include "path-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return unit_name_to_prefix_and_instance(u->id);
}
static char *specifier_prefix(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return unit_name_to_prefix(u->id);
}
static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
Unit *u = userdata;
char *p, *r;
assert(u);
p = unit_name_to_prefix(u->id);
if (!p)
return NULL;
r = unit_name_unescape(p);
free(p);
return r;
}
static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->instance)
return unit_name_unescape(u->instance);
return strdup("");
}
static char *specifier_filename(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->instance)
return unit_name_path_unescape(u->instance);
return unit_name_to_path(u->id);
}
static char *specifier_cgroup(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return unit_default_cgroup_path(u);
}
static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
Unit *u = userdata;
char *p;
assert(u);
if (specifier == 'r')
return strdup(u->manager->cgroup_hierarchy);
if (path_get_parent(u->manager->cgroup_hierarchy, &p) < 0)
return strdup("");
if (streq(p, "/")) {
free(p);
return strdup("");
}
return p;
}
static char *specifier_runtime(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->manager->running_as == MANAGER_USER) {
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (e)
return strdup(e);
}
return strdup("/run");
}
static char *specifier_user_name(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username;
/* get USER env from our own env if set */
if (!s->exec_context.user)
return getusername_malloc();
/* fish username from passwd */
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, NULL, NULL);
if (r < 0)
return NULL;
return strdup(username);
}
static char *specifier_user_home(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username, *home;
/* return HOME if set, otherwise from passwd */
if (!s->exec_context.user) {
char *h;
r = get_home_dir(&h);
if (r < 0)
return NULL;
return h;
}
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, &home, NULL);
if (r < 0)
return NULL;
return strdup(home);
}
static char *specifier_user_shell(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username, *shell;
/* return HOME if set, otherwise from passwd */
if (!s->exec_context.user) {
char *sh;
r = get_shell(&sh);
if (r < 0)
return strdup("/bin/sh");
return sh;
}
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, NULL, &shell);
if (r < 0)
return strdup("/bin/sh");
return strdup(shell);
}
char *unit_name_printf(Unit *u, const char* format) {
/*
* This will use the passed string as format string and
* replace the following specifiers:
*
* %n: the full id of the unit (foo@bar.waldo)
* %N: the id of the unit without the suffix (foo@bar)
* %p: the prefix (foo)
* %i: the instance (bar)
*/
const Specifier table[] = {
{ 'n', specifier_string, u->id },
{ 'N', specifier_prefix_and_instance, NULL },
{ 'p', specifier_prefix, NULL },
{ 'i', specifier_string, u->instance },
{ 0, NULL, NULL }
};
assert(u);
assert(format);
return specifier_printf(format, table, u);
}
char *unit_full_printf(Unit *u, const char *format) {
/* This is similar to unit_name_printf() but also supports
* unescaping. Also, adds a couple of additional codes:
*
* %f the the instance if set, otherwise the id
* %c cgroup path of unit
* %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
* %R parent of root cgroup path (e.g. "/usr/lennart/shared")
* %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
* %u the username of the configured user or running user
* %h the homedir of the configured user or running user
* %s the shell of the configured user or running user
*/
const Specifier table[] = {
{ 'n', specifier_string, u->id },
{ 'N', specifier_prefix_and_instance, NULL },
{ 'p', specifier_prefix, NULL },
{ 'P', specifier_prefix_unescaped, NULL },
{ 'i', specifier_string, u->instance },
{ 'I', specifier_instance_unescaped, NULL },
{ 'f', specifier_filename, NULL },
{ 'c', specifier_cgroup, NULL },
{ 'r', specifier_cgroup_root, NULL },
{ 'R', specifier_cgroup_root, NULL },
{ 't', specifier_runtime, NULL },
{ 'u', specifier_user_name, NULL },
{ 'h', specifier_user_home, NULL },
{ 's', specifier_user_shell, NULL },
{ 0, NULL, NULL }
};
assert(u);
assert(format);
return specifier_printf(format, table, u);
}
char **unit_full_printf_strv(Unit *u, char **l) {
size_t n;
char **r, **i, **j;
/* Applies unit_full_printf to every entry in l */
assert(u);
n = strv_length(l);
r = new(char*, n+1);
if (!r)
return NULL;
for (i = l, j = r; *i; i++, j++) {
*j = unit_full_printf(u, *i);
if (!*j)
goto fail;
}
*j = NULL;
return r;
fail:
for (j--; j >= r; j--)
free(*j);
free(r);
return NULL;
}

28
src/core/unit-printf.h Normal file
View File

@ -0,0 +1,28 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
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 "unit.h"
char *unit_name_printf(Unit *u, const char* text);
char *unit_full_printf(Unit *u, const char *text);
char **unit_full_printf_strv(Unit *u, char **l);

View File

@ -40,7 +40,6 @@
#include "load-dropin.h" #include "load-dropin.h"
#include "log.h" #include "log.h"
#include "unit-name.h" #include "unit-name.h"
#include "specifier.h"
#include "dbus-unit.h" #include "dbus-unit.h"
#include "special.h" #include "special.h"
#include "cgroup-util.h" #include "cgroup-util.h"
@ -1965,7 +1964,7 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) {
return 0; return 0;
} }
static char *default_cgroup_path(Unit *u) { char *unit_default_cgroup_path(Unit *u) {
char *p; char *p;
assert(u); assert(u);
@ -1998,7 +1997,7 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) {
return r; return r;
if (!path) { if (!path) {
path = default_cgroup_path(u); path = unit_default_cgroup_path(u);
ours = true; ours = true;
} }
@ -2060,7 +2059,8 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
if (!(b->controller = strdup(controller))) if (!(b->controller = strdup(controller)))
goto fail; goto fail;
if (!(b->path = default_cgroup_path(u))) b->path = unit_default_cgroup_path(u);
if (!b->path)
goto fail; goto fail;
b->ours = true; b->ours = true;
@ -2217,256 +2217,6 @@ int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
return 0; return 0;
} }
static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return unit_name_to_prefix_and_instance(u->id);
}
static char *specifier_prefix(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return unit_name_to_prefix(u->id);
}
static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
Unit *u = userdata;
char *p, *r;
assert(u);
if (!(p = unit_name_to_prefix(u->id)))
return NULL;
r = unit_name_unescape(p);
free(p);
return r;
}
static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->instance)
return unit_name_unescape(u->instance);
return strdup("");
}
static char *specifier_filename(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->instance)
return unit_name_path_unescape(u->instance);
return unit_name_to_path(u->id);
}
static char *specifier_cgroup(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
return default_cgroup_path(u);
}
static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
Unit *u = userdata;
char *p;
assert(u);
if (specifier == 'r')
return strdup(u->manager->cgroup_hierarchy);
if (path_get_parent(u->manager->cgroup_hierarchy, &p) < 0)
return strdup("");
if (streq(p, "/")) {
free(p);
return strdup("");
}
return p;
}
static char *specifier_runtime(char specifier, void *data, void *userdata) {
Unit *u = userdata;
assert(u);
if (u->manager->running_as == MANAGER_USER) {
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (e)
return strdup(e);
}
return strdup("/run");
}
static char *specifier_user_name(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username;
/* get USER env from our own env if set */
if (!s->exec_context.user)
return getusername_malloc();
/* fish username from passwd */
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, NULL, NULL);
if (r < 0)
return NULL;
return strdup(username);
}
static char *specifier_user_home(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username, *home;
/* return HOME if set, otherwise from passwd */
if (!s->exec_context.user) {
char *h;
r = get_home_dir(&h);
if (r < 0)
return NULL;
return h;
}
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, &home, NULL);
if (r < 0)
return NULL;
return strdup(home);
}
static char *specifier_user_shell(char specifier, void *data, void *userdata) {
Service *s = userdata;
int r;
const char *username, *shell;
/* return HOME if set, otherwise from passwd */
if (!s->exec_context.user) {
char *sh;
r = get_shell(&sh);
if (r < 0)
return strdup("/bin/sh");
return sh;
}
username = s->exec_context.user;
r = get_user_creds(&username, NULL, NULL, NULL, &shell);
if (r < 0)
return strdup("/bin/sh");
return strdup(shell);
}
char *unit_name_printf(Unit *u, const char* format) {
/*
* This will use the passed string as format string and
* replace the following specifiers:
*
* %n: the full id of the unit (foo@bar.waldo)
* %N: the id of the unit without the suffix (foo@bar)
* %p: the prefix (foo)
* %i: the instance (bar)
*/
const Specifier table[] = {
{ 'n', specifier_string, u->id },
{ 'N', specifier_prefix_and_instance, NULL },
{ 'p', specifier_prefix, NULL },
{ 'i', specifier_string, u->instance },
{ 0, NULL, NULL }
};
assert(u);
assert(format);
return specifier_printf(format, table, u);
}
char *unit_full_printf(Unit *u, const char *format) {
/* This is similar to unit_name_printf() but also supports
* unescaping. Also, adds a couple of additional codes:
*
* %f the the instance if set, otherwise the id
* %c cgroup path of unit
* %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
* %R parent of root cgroup path (e.g. "/usr/lennart/shared")
* %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
* %u the username of the configured user or running user
* %h the homedir of the configured user or running user
* %s the shell of the configured user or running user
*/
const Specifier table[] = {
{ 'n', specifier_string, u->id },
{ 'N', specifier_prefix_and_instance, NULL },
{ 'p', specifier_prefix, NULL },
{ 'P', specifier_prefix_unescaped, NULL },
{ 'i', specifier_string, u->instance },
{ 'I', specifier_instance_unescaped, NULL },
{ 'f', specifier_filename, NULL },
{ 'c', specifier_cgroup, NULL },
{ 'r', specifier_cgroup_root, NULL },
{ 'R', specifier_cgroup_root, NULL },
{ 't', specifier_runtime, NULL },
{ 'u', specifier_user_name, NULL },
{ 'h', specifier_user_home, NULL },
{ 's', specifier_user_shell, NULL },
{ 0, NULL, NULL }
};
assert(u);
assert(format);
return specifier_printf(format, table, u);
}
char **unit_full_printf_strv(Unit *u, char **l) {
size_t n;
char **r, **i, **j;
/* Applies unit_full_printf to every entry in l */
assert(u);
n = strv_length(l);
if (!(r = new(char*, n+1)))
return NULL;
for (i = l, j = r; *i; i++, j++)
if (!(*j = unit_full_printf(u, *i)))
goto fail;
*j = NULL;
return r;
fail:
for (j--; j >= r; j--)
free(*j);
free(r);
return NULL;
}
int unit_watch_bus_name(Unit *u, const char *name) { int unit_watch_bus_name(Unit *u, const char *name) {
assert(u); assert(u);
assert(name); assert(name);

View File

@ -495,10 +495,6 @@ char *unit_dbus_path(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found); int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
int unit_get_related_unit(Unit *u, const char *type, Unit **_found); int unit_get_related_unit(Unit *u, const char *type, Unit **_found);
char *unit_name_printf(Unit *u, const char* text);
char *unit_full_printf(Unit *u, const char *text);
char **unit_full_printf_strv(Unit *u, char **l);
bool unit_can_serialize(Unit *u); bool unit_can_serialize(Unit *u);
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5); void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5);
@ -522,6 +518,8 @@ bool unit_pending_active(Unit *u);
int unit_add_default_target_dependency(Unit *u, Unit *target); int unit_add_default_target_dependency(Unit *u, Unit *target);
char *unit_default_cgroup_path(Unit *u);
int unit_following_set(Unit *u, Set **s); int unit_following_set(Unit *u, Set **s);
void unit_trigger_on_failure(Unit *u); void unit_trigger_on_failure(Unit *u);