#include "unit.h"
#include "unit-name.h"
#include "special.h"
-#include "exit-status.h"
-#include "def.h"
-#include "env-util.h"
-#include "fileio.h"
#include "hashmap.h"
typedef enum RunlevelType {
const RunlevelType type;
} rcnd_table[] = {
/* Standard SysV runlevels for start-up */
- { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
- { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
- { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
- { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
- { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
+ { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
+ { "rc2.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc3.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc4.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc5.d", SPECIAL_GRAPHICAL_TARGET, RUNLEVEL_UP },
/* Standard SysV runlevels for shutdown */
{ "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN },
return 1;
}
+static int add_alias(const char *service, const char *alias) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ assert(service);
+ assert(alias);
+
+ link = strjoin(arg_dest, "/", alias, NULL);
+ if (!link)
+ return log_oom();
+
+ r = symlink(service, link);
+ if (r < 0) {
+ if (errno == EEXIST)
+ return 0;
+ return -errno;
+ }
+
+ return 1;
+}
+
static int generate_unit_file(SysvStub *s) {
char **p;
_cleanup_fclose_ FILE *f = NULL;
if (!unit)
return log_oom();
- f = fopen(unit, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", unit);
- return -errno;
+ /* We might already have a symlink with the same name from a Provides:,
+ * or from backup files like /etc/init.d/foo.bak. Real scripts always win,
+ * so remove an existing link */
+ if (is_symlink(unit) > 0) {
+ log_warning("Overwriting existing symlink %s with real service", unit);
+ (void) unlink(unit);
}
+ f = fopen(unit, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
+
fprintf(f,
"# Automatically generated by systemd-sysv-generator\n\n"
"[Unit]\n"
"RemainAfterExit=%s\n",
yes_no(!s->pid_file));
- if (s->sysv_start_priority > 0)
- fprintf(f, "SysVStartPriority=%d\n", s->sysv_start_priority);
-
if (s->pid_file)
fprintf(f, "PIDFile=%s\n", s->pid_file);
"time", SPECIAL_TIME_SYNC_TARGET,
};
- unsigned i;
- char *r;
+ char *filename_no_sh, *e, *r;
const char *n;
+ unsigned i;
assert(name);
assert(_r);
goto finish;
}
+ /* strip ".sh" suffix from file name for comparison */
+ filename_no_sh = strdupa(filename);
+ e = endswith(filename_no_sh, ".sh");
+ if (e) {
+ *e = '\0';
+ filename = filename_no_sh;
+ }
+
/* If we don't know this name, fallback heuristics to figure
* out whether something is a target or a service alias. */
/* Facilities starting with $ are most likely targets */
r = unit_name_build(n, NULL, ".target");
- } else if (filename && streq(name, filename))
+ } else if (streq_ptr(n, filename))
/* Names equaling the file name of the services are redundant */
return 0;
else
/* Everything else we assume to be normal service names */
r = sysv_translate_name(n);
-
if (!r)
return -ENOMEM;
if (!f)
return errno == ENOENT ? 0 : -errno;
+ log_debug("Loading SysV script %s", s->path);
+
while (!feof(f)) {
char l[LINE_MAX], *t;
return -ENOMEM;
r = sysv_translate_facility(n, basename(s->path), &m);
-
if (r < 0)
return r;
-
if (r == 0)
continue;
- if (unit_name_to_type(m) != UNIT_SERVICE) {
+ if (unit_name_to_type(m) == UNIT_SERVICE) {
+ log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
+ r = add_alias(s->name, m);
+ } else {
/* NB: SysV targets
* which are provided
* by a service are
return 0;
}
-static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
+static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
char **path;
- STRV_FOREACH(path, lp.sysvinit_path) {
+ STRV_FOREACH(path, lp->sysvinit_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
d = opendir(*path);
if (!d) {
if (errno != ENOENT)
- log_warning("opendir(%s) failed: %m", *path);
+ log_warning_errno(errno, "opendir(%s) failed: %m", *path);
continue;
}
while ((de = readdir(d))) {
- SysvStub *service;
- struct stat st;
_cleanup_free_ char *fpath = NULL, *name = NULL;
+ _cleanup_free_ SysvStub *service = NULL;
+ struct stat st;
int r;
- if (ignore_file(de->d_name))
+ if (hidden_file(de->d_name))
continue;
- fpath = strjoin(*path, "/", de->d_name, NULL);
- if (!fpath)
- return log_oom();
-
- if (stat(fpath, &st) < 0)
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
continue;
+ }
if (!(st.st_mode & S_IXUSR))
continue;
+ if (!S_ISREG(st.st_mode))
+ continue;
+
name = sysv_translate_name(de->d_name);
if (!name)
return log_oom();
if (hashmap_contains(all_services, name))
continue;
+ fpath = strjoin(*path, "/", de->d_name, NULL);
+ if (!fpath)
+ return log_oom();
+
+ if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) {
+ log_debug("Native unit for %s already exists, skipping", name);
+ continue;
+ }
+
service = new0(SysvStub, 1);
if (!service)
return log_oom();
return log_oom();
name = fpath = NULL;
+ service = NULL;
}
}
return 0;
}
-static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) {
+static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
char **p;
unsigned i;
_cleanup_closedir_ DIR *d = NULL;
_cleanup_set_free_ Set *shutdown_services = NULL;
int r = 0;
- STRV_FOREACH(p, lp.sysvrcnd_path)
+ STRV_FOREACH(p, lp->sysvrcnd_path)
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
struct dirent *de;
d = opendir(path);
if (!d) {
if (errno != ENOENT)
- log_warning("opendir(%s) failed: %m", path);
+ log_warning_errno(errno, "opendir(%s) failed: %m", path);
continue;
}
while ((de = readdir(d))) {
int a, b;
- if (ignore_file(de->d_name))
+ if (hidden_file(de->d_name))
continue;
if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
service = hashmap_get(all_services, name);
if (!service){
- log_warning("Could not find init script for %s", name);
+ log_debug("Ignoring %s symlink in %s, not generating %s.",
+ de->d_name, rcnd_table[i].path, name);
continue;
}
return EXIT_FAILURE;
}
- r = enumerate_sysv(lp, all_services);
+ r = enumerate_sysv(&lp, all_services);
if (r < 0) {
log_error("Failed to generate units for all init scripts.");
return EXIT_FAILURE;
}
- r = set_dependencies_from_rcnd(lp, all_services);
+ r = set_dependencies_from_rcnd(&lp, all_services);
if (r < 0) {
log_error("Failed to read runlevels from rcnd links.");
return EXIT_FAILURE;
q = load_sysv(service);
if (q < 0)
continue;
+ }
+ HASHMAP_FOREACH(service, all_services, j) {
q = fix_order(service, all_services);
if (q < 0)
continue;