From: Michal Sekletar Date: Fri, 13 Jul 2012 13:59:26 +0000 (+0200) Subject: systemd: enable/disable instances of template X-Git-Tag: v188~80 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=29283ea4cf5df20aa0ea9e24e3cb7035bf4c4a04 systemd: enable/disable instances of template https://bugzilla.redhat.com/show_bug.cgi?id=752774 --- diff --git a/man/systemctl.xml b/man/systemctl.xml index 3c0a7950a..c5fae825a 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -682,24 +682,29 @@ enable [NAME...] - Enable one or more - unit files, as specified on the + Enable one or + more unit files or unit file + instances, as specified on the command line. This will create a - number of symlinks as encoded in the - [Install] sections - of the unit files. After the symlinks - have been created the systemd - configuration is reloaded (in a way - that is equivalent to - daemon-reload) to - ensure the changes are taken into + number of symlinks as encoded in + the [Install] + sections of the unit files. After + the symlinks have been created the + systemd configuration is reloaded + (in a way that is equivalent to + daemon-reload) + to ensure the changes are taken into account immediately. Note that this does not have the effect that any of the units enabled are also started at - the same time. If this is desired a - separate start - command must be invoked for the - unit. + the same time. If this is desired + a separate start + command must be invoked for the unit. + Also note that in case of instance + enablement, symlinks named same as + instances are created in install + location, however they all point to + the same template unit file. This command will print the actions executed. This diff --git a/src/shared/install.c b/src/shared/install.c index a3b75243d..ef1c3f584 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -196,7 +196,8 @@ static int remove_marked_symlinks_fd( const char *config_path, bool *deleted, UnitFileChange **changes, - unsigned *n_changes) { + unsigned *n_changes, + char** files) { int r = 0; DIR *d; @@ -255,7 +256,7 @@ static int remove_marked_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files); free(p); if (r == 0) @@ -288,6 +289,9 @@ static int remove_marked_symlinks_fd( set_get(remove_symlinks_to, dest) || set_get(remove_symlinks_to, path_get_file_name(dest)); + if (unit_name_is_instance(p)) + found = found && strv_contains(files, path_get_file_name(p)); + if (found) { if (unlink(p) < 0 && errno != ENOENT) { @@ -326,7 +330,8 @@ static int remove_marked_symlinks( Set *remove_symlinks_to, const char *config_path, UnitFileChange **changes, - unsigned *n_changes) { + unsigned *n_changes, + char** files) { int fd, r = 0; bool deleted; @@ -351,7 +356,7 @@ static int remove_marked_symlinks( } /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files); if (r == 0) r = q; } while (deleted); @@ -717,7 +722,7 @@ int unit_file_unmask( finish: - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); if (r == 0) r = q; @@ -1094,8 +1099,48 @@ static int unit_file_search( if (r >= 0) info->path = path; - else + else { + if (r == -ENOENT && unit_name_is_instance(info->name)) { + /* unit file doesn't exist, however instance enablement was request */ + /* we will check if it is possible to load template unit file */ + char *template = NULL, + *template_path = NULL, + *template_dir = NULL; + + template = unit_name_template(info->name); + if (!template) { + free(path); + return -ENOMEM; + } + + /* we will reuse path variable since we don't need it anymore */ + template_dir = path; + *(strrchr(path, '/') + 1) = '\0'; + + template_path = strjoin(template_dir, template, NULL); + if (!template_path) { + free(path); + free(template); + return -ENOMEM; + } + + /* let's try to load template unit */ + r = unit_file_load(c, info, template_path, allow_symlink); + if (r >= 0) { + info->path = strdup(template_path); + if (!info->path) { + free(path); + free(template); + free(template_path); + return -ENOMEM; + } + } + + free(template); + free(template_path); + } free(path); + } if (r != -ENOENT && r != -ELOOP) return r; @@ -1419,7 +1464,20 @@ static int install_context_mark_for_removal( } else if (r >= 0) r += q; - q = mark_symlink_for_removal(remove_symlinks_to, i->name); + if (unit_name_is_instance(i->name)) { + char *unit_file = NULL; + + unit_file = path_get_file_name(i->path); + + if (unit_name_is_instance(unit_file)) + /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */ + q = mark_symlink_for_removal(remove_symlinks_to, i->name); + else + /* does not exist, thus we will mark for removal symlinks to template unit file */ + q = mark_symlink_for_removal(remove_symlinks_to, unit_file); + } else + q = mark_symlink_for_removal(remove_symlinks_to, i->name); + if (r >= 0 && q < 0) r = q; } @@ -1511,7 +1569,7 @@ int unit_file_disable( r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); if (r == 0) r = q; @@ -1563,7 +1621,7 @@ int unit_file_reenable( goto finish; } - r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); /* Returns number of symlinks that where supposed to be installed. */ q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); @@ -1813,7 +1871,7 @@ int unit_file_preset( r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); if (r == 0) r = q; diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c index fcf5902c7..e8328c321 100644 --- a/src/shared/unit-name.c +++ b/src/shared/unit-name.c @@ -341,6 +341,18 @@ bool unit_name_is_template(const char *n) { return p[1] == '.'; } +bool unit_name_is_instance(const char *n) { + const char *p; + + assert(n); + + p = strchr(n, '@'); + if (!p) + return false; + + return p[1] != '.'; +} + char *unit_name_replace_instance(const char *f, const char *i) { const char *p, *e; char *r, *k; diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h index f899f8652..7be346590 100644 --- a/src/shared/unit-name.h +++ b/src/shared/unit-name.h @@ -79,6 +79,7 @@ char *unit_name_path_escape(const char *f); char *unit_name_path_unescape(const char *f); bool unit_name_is_template(const char *n); +bool unit_name_is_instance(const char *n); char *unit_name_replace_instance(const char *f, const char *i);