+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
#include "alloc-util.h"
#include "dirent-util.h"
+#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
+#include "generator.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "install.h"
#include "path-util.h"
#include "set.h"
#include "special.h"
+#include "specifier.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub);
static void free_sysvstub_hashmapp(Hashmap **h) {
- SysvStub *stub;
-
- while ((stub = hashmap_steal_first(*h)))
- free_sysvstub(stub);
-
- hashmap_free(*h);
-}
-
-static int add_symlink(const char *service, const char *where) {
- const char *from, *to;
- int r;
-
- assert(service);
- assert(where);
-
- from = strjoina(arg_dest, "/", service);
- to = strjoina(arg_dest, "/", where, ".wants/", service);
-
- mkdir_parents_label(to, 0755);
-
- r = symlink(from, to);
- if (r < 0) {
- if (errno == EEXIST)
- return 0;
-
- return -errno;
- }
-
- return 1;
+ hashmap_free_with_destructor(*h, free_sysvstub);
}
static int add_alias(const char *service, const char *alias) {
}
static int generate_unit_file(SysvStub *s) {
+ _cleanup_free_ char *path_escaped = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit;
char **p;
if (!s->loaded)
return 0;
+ path_escaped = specifier_escape(s->path);
+ if (!path_escaped)
+ return log_oom();
+
unit = strjoina(arg_dest, "/", s->name);
/* We might already have a symlink with the same name from a Provides:,
"[Unit]\n"
"Documentation=man:systemd-sysv-generator(8)\n"
"SourcePath=%s\n",
- s->path);
+ path_escaped);
- if (s->description)
- fprintf(f, "Description=%s\n", s->description);
+ if (s->description) {
+ _cleanup_free_ char *t;
+
+ t = specifier_escape(s->description);
+ if (!t)
+ return log_oom();
+
+ fprintf(f, "Description=%s\n", t);
+ }
STRV_FOREACH(p, s->before)
fprintf(f, "Before=%s\n", *p);
"RemainAfterExit=%s\n",
yes_no(!s->pid_file));
- if (s->pid_file)
- fprintf(f, "PIDFile=%s\n", s->pid_file);
+ if (s->pid_file) {
+ _cleanup_free_ char *t;
+
+ t = specifier_escape(s->pid_file);
+ if (!t)
+ return log_oom();
+
+ fprintf(f, "PIDFile=%s\n", t);
+ }
+
+ /* Consider two special LSB exit codes a clean exit */
+ if (s->has_lsb)
+ fprintf(f,
+ "SuccessExitStatus=%i %i\n",
+ EXIT_NOTINSTALLED,
+ EXIT_NOTCONFIGURED);
fprintf(f,
"ExecStart=%s start\n"
"ExecStop=%s stop\n",
- s->path, s->path);
+ path_escaped, path_escaped);
if (s->reload)
- fprintf(f, "ExecReload=%s reload\n", s->path);
+ fprintf(f, "ExecReload=%s reload\n", path_escaped);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit %s: %m", unit);
- STRV_FOREACH(p, s->wanted_by) {
- r = add_symlink(s->name, *p);
- if (r < 0)
- log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
- }
+ STRV_FOREACH(p, s->wanted_by)
+ (void) generator_add_symlink(arg_dest, *p, "wants", s->name);
return 1;
}
if (res)
*res = 0;
- if (unit_name_mangle(c, UNIT_NAME_NOGLOB, &res) < 0)
+ if (unit_name_mangle(c, 0, &res) < 0)
return NULL;
return res;
}
-static int sysv_translate_facility(const char *name, const char *filename, char **ret) {
+static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, char **ret) {
/* We silently ignore the $ prefix here. According to the LSB
* spec it simply indicates whether something is a
"time", SPECIAL_TIME_SYNC_TARGET,
};
+ const char *filename;
char *filename_no_sh, *e, *m;
const char *n;
unsigned i;
int r;
assert(name);
- assert(filename);
+ assert(s);
assert(ret);
+ filename = basename(s->path);
+
n = *name == '$' ? name + 1 : name;
for (i = 0; i < ELEMENTSOF(table); i += 2) {
if (!streq(table[i], n))
continue;
- if (!table[i+1])
+ if (!table[i+1]) {
+ *ret = NULL;
return 0;
+ }
m = strdup(table[i+1]);
if (!m)
if (*name == '$') {
r = unit_name_build(n, NULL, ".target", ret);
if (r < 0)
- return log_error_errno(r, "Failed to build name: %m");
+ return log_error_errno(r, "[%s:%u] Could not build name for facility %s: %m", s->path, line, name);
- return r;
+ return 1;
}
/* Strip ".sh" suffix from file name for comparison */
}
/* Names equaling the file name of the services are redundant */
- if (streq_ptr(n, filename))
+ if (streq_ptr(n, filename)) {
+ *ret = NULL;
return 0;
+ }
/* Everything else we assume to be normal service names */
m = sysv_translate_name(n);
r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
- return log_error_errno(r, "Failed to parse word from provides string: %m");
+ return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line);
if (r == 0)
break;
- r = sysv_translate_facility(word, basename(s->path), &m);
+ r = sysv_translate_facility(s, line, word, &m);
if (r <= 0) /* continue on error */
continue;
r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
if (r < 0)
return log_oom();
+ r = strv_extend(&s->wants, SPECIAL_NETWORK_TARGET);
+ if (r < 0)
+ return log_oom();
}
break;
r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
- return log_error_errno(r, "Failed to parse word from provides string: %m");
+ return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line);
if (r == 0)
break;
- r = sysv_translate_facility(word, basename(s->path), &m);
+ r = sysv_translate_facility(s, line, word, &m);
if (r <= 0) /* continue on error */
continue;
continue;
}
- if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
+ if (IN_SET(state, LSB_DESCRIPTION, LSB) && streq(t, "### END INIT INFO")) {
state = NORMAL;
continue;
}
char *d = NULL;
if (chkconfig_description)
- d = strjoin(chkconfig_description, " ", j, NULL);
+ d = strjoin(chkconfig_description, " ", j);
else
d = strdup(j);
if (!d)
chkconfig_description = d;
}
- } else if (state == LSB || state == LSB_DESCRIPTION) {
+ } else if (IN_SET(state, LSB, LSB_DESCRIPTION)) {
if (startswith_no_case(t, "Provides:")) {
state = LSB;
char *d = NULL;
if (long_description)
- d = strjoin(long_description, " ", t, NULL);
+ d = strjoin(long_description, " ", t);
else
d = strdup(j);
if (!d)
if (!path_strv_resolve_uniq(l, NULL))
return log_oom();
- *ret = l;
- l = NULL;
+ *ret = TAKE_PTR(l);
return 0;
}
continue;
}
- fpath = strjoin(*path, "/", de->d_name, NULL);
+ fpath = strjoin(*path, "/", de->d_name);
if (!fpath)
return log_oom();
return log_oom();
service->sysv_start_priority = -1;
- service->name = name;
- service->path = fpath;
- name = fpath = NULL;
+ service->name = TAKE_PTR(name);
+ service->path = TAKE_PTR(fpath);
r = hashmap_put(all_services, service->name, service);
if (r < 0)
_cleanup_free_ char *path = NULL;
struct dirent *de;
- path = strjoin(*p, "/", rcnd_table[i].path, NULL);
+ path = strjoin(*p, "/", rcnd_table[i].path);
if (!path) {
r = log_oom();
goto finish;
if (a < 0 || b < 0)
continue;
- fpath = strjoin(*p, "/", de->d_name, NULL);
+ fpath = strjoin(*p, "/", de->d_name);
if (!fpath) {
r = log_oom();
goto finish;
if (argc > 1)
arg_dest = argv[3];
- log_set_target(LOG_TARGET_SAFE);
+ log_set_prohibit_ipc(true);
+ log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();