LCOV - code coverage report
Current view: top level - core - scope.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 2 252 0.8 %
Date: 2015-07-29 18:47:03 Functions: 4 29 13.8 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <unistd.h>
      24             : 
      25             : #include "unit.h"
      26             : #include "scope.h"
      27             : #include "log.h"
      28             : #include "dbus-scope.h"
      29             : #include "special.h"
      30             : #include "unit-name.h"
      31             : #include "load-dropin.h"
      32             : 
      33             : static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
      34             :         [SCOPE_DEAD] = UNIT_INACTIVE,
      35             :         [SCOPE_RUNNING] = UNIT_ACTIVE,
      36             :         [SCOPE_ABANDONED] = UNIT_ACTIVE,
      37             :         [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
      38             :         [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
      39             :         [SCOPE_FAILED] = UNIT_FAILED
      40             : };
      41             : 
      42             : static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
      43             : 
      44           0 : static void scope_init(Unit *u) {
      45           0 :         Scope *s = SCOPE(u);
      46             : 
      47           0 :         assert(u);
      48           0 :         assert(u->load_state == UNIT_STUB);
      49             : 
      50           0 :         s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
      51             : 
      52           0 :         UNIT(s)->ignore_on_isolate = true;
      53           0 :         UNIT(s)->ignore_on_snapshot = true;
      54           0 : }
      55             : 
      56           0 : static void scope_done(Unit *u) {
      57           0 :         Scope *s = SCOPE(u);
      58             : 
      59           0 :         assert(u);
      60             : 
      61           0 :         free(s->controller);
      62             : 
      63           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
      64           0 : }
      65             : 
      66           0 : static int scope_arm_timer(Scope *s) {
      67             :         int r;
      68             : 
      69           0 :         assert(s);
      70             : 
      71           0 :         if (s->timeout_stop_usec <= 0) {
      72           0 :                 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
      73           0 :                 return 0;
      74             :         }
      75             : 
      76           0 :         if (s->timer_event_source) {
      77           0 :                 r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
      78           0 :                 if (r < 0)
      79           0 :                         return r;
      80             : 
      81           0 :                 return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
      82             :         }
      83             : 
      84           0 :         r = sd_event_add_time(
      85           0 :                         UNIT(s)->manager->event,
      86             :                         &s->timer_event_source,
      87             :                         CLOCK_MONOTONIC,
      88           0 :                         now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
      89             :                         scope_dispatch_timer, s);
      90           0 :         if (r < 0)
      91           0 :                 return r;
      92             : 
      93           0 :         (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");
      94             : 
      95           0 :         return 0;
      96             : }
      97             : 
      98           0 : static void scope_set_state(Scope *s, ScopeState state) {
      99             :         ScopeState old_state;
     100           0 :         assert(s);
     101             : 
     102           0 :         old_state = s->state;
     103           0 :         s->state = state;
     104             : 
     105           0 :         if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
     106           0 :                 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
     107             : 
     108           0 :         if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED))
     109           0 :                 unit_unwatch_all_pids(UNIT(s));
     110             : 
     111           0 :         if (state != old_state)
     112           0 :                 log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
     113             : 
     114           0 :         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
     115           0 : }
     116             : 
     117           0 : static int scope_add_default_dependencies(Scope *s) {
     118             :         int r;
     119             : 
     120           0 :         assert(s);
     121             : 
     122             :         /* Make sure scopes are unloaded on shutdown */
     123           0 :         r = unit_add_two_dependencies_by_name(
     124             :                         UNIT(s),
     125             :                         UNIT_BEFORE, UNIT_CONFLICTS,
     126             :                         SPECIAL_SHUTDOWN_TARGET, NULL, true);
     127           0 :         if (r < 0)
     128           0 :                 return r;
     129             : 
     130           0 :         return 0;
     131             : }
     132             : 
     133           0 : static int scope_verify(Scope *s) {
     134           0 :         assert(s);
     135             : 
     136           0 :         if (UNIT(s)->load_state != UNIT_LOADED)
     137           0 :                 return 0;
     138             : 
     139           0 :         if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
     140           0 :                 log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
     141           0 :                 return -EINVAL;
     142             :         }
     143             : 
     144           0 :         return 0;
     145             : }
     146             : 
     147           0 : static int scope_load(Unit *u) {
     148           0 :         Scope *s = SCOPE(u);
     149             :         int r;
     150             : 
     151           0 :         assert(s);
     152           0 :         assert(u->load_state == UNIT_STUB);
     153             : 
     154           0 :         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
     155           0 :                 return -ENOENT;
     156             : 
     157           0 :         u->load_state = UNIT_LOADED;
     158             : 
     159           0 :         r = unit_load_dropin(u);
     160           0 :         if (r < 0)
     161           0 :                 return r;
     162             : 
     163           0 :         r = unit_patch_contexts(u);
     164           0 :         if (r < 0)
     165           0 :                 return r;
     166             : 
     167           0 :         r = unit_add_default_slice(u, &s->cgroup_context);
     168           0 :         if (r < 0)
     169           0 :                 return r;
     170             : 
     171           0 :         if (u->default_dependencies) {
     172           0 :                 r = scope_add_default_dependencies(s);
     173           0 :                 if (r < 0)
     174           0 :                         return r;
     175             :         }
     176             : 
     177           0 :         return scope_verify(s);
     178             : }
     179             : 
     180           0 : static int scope_coldplug(Unit *u) {
     181           0 :         Scope *s = SCOPE(u);
     182             :         int r;
     183             : 
     184           0 :         assert(s);
     185           0 :         assert(s->state == SCOPE_DEAD);
     186             : 
     187           0 :         if (s->deserialized_state != s->state) {
     188             : 
     189           0 :                 if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
     190           0 :                         r = scope_arm_timer(s);
     191           0 :                         if (r < 0)
     192           0 :                                 return r;
     193             :                 }
     194             : 
     195           0 :                 if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
     196           0 :                         unit_watch_all_pids(UNIT(s));
     197             : 
     198           0 :                 scope_set_state(s, s->deserialized_state);
     199             :         }
     200             : 
     201           0 :         return 0;
     202             : }
     203             : 
     204           0 : static void scope_dump(Unit *u, FILE *f, const char *prefix) {
     205           0 :         Scope *s = SCOPE(u);
     206             : 
     207           0 :         assert(s);
     208           0 :         assert(f);
     209             : 
     210           0 :         fprintf(f,
     211             :                 "%sScope State: %s\n"
     212             :                 "%sResult: %s\n",
     213             :                 prefix, scope_state_to_string(s->state),
     214             :                 prefix, scope_result_to_string(s->result));
     215             : 
     216           0 :         cgroup_context_dump(&s->cgroup_context, f, prefix);
     217           0 :         kill_context_dump(&s->kill_context, f, prefix);
     218           0 : }
     219             : 
     220           0 : static void scope_enter_dead(Scope *s, ScopeResult f) {
     221           0 :         assert(s);
     222             : 
     223           0 :         if (f != SCOPE_SUCCESS)
     224           0 :                 s->result = f;
     225             : 
     226           0 :         scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
     227           0 : }
     228             : 
     229           0 : static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
     230           0 :         bool skip_signal = false;
     231             :         int r;
     232             : 
     233           0 :         assert(s);
     234             : 
     235           0 :         if (f != SCOPE_SUCCESS)
     236           0 :                 s->result = f;
     237             : 
     238           0 :         unit_watch_all_pids(UNIT(s));
     239             : 
     240             :         /* If we have a controller set let's ask the controller nicely
     241             :          * to terminate the scope, instead of us going directly into
     242             :          * SIGTERM beserk mode */
     243           0 :         if (state == SCOPE_STOP_SIGTERM)
     244           0 :                 skip_signal = bus_scope_send_request_stop(s) > 0;
     245             : 
     246           0 :         if (!skip_signal) {
     247           0 :                 r = unit_kill_context(
     248             :                                 UNIT(s),
     249             :                                 &s->kill_context,
     250             :                                 state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE,
     251             :                                 -1, -1, false);
     252           0 :                 if (r < 0)
     253           0 :                         goto fail;
     254             :         } else
     255           0 :                 r = 1;
     256             : 
     257           0 :         if (r > 0) {
     258           0 :                 r = scope_arm_timer(s);
     259           0 :                 if (r < 0)
     260           0 :                         goto fail;
     261             : 
     262           0 :                 scope_set_state(s, state);
     263           0 :         } else if (state == SCOPE_STOP_SIGTERM)
     264           0 :                 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
     265             :         else
     266           0 :                 scope_enter_dead(s, SCOPE_SUCCESS);
     267             : 
     268           0 :         return;
     269             : 
     270             : fail:
     271           0 :         log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
     272             : 
     273           0 :         scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
     274             : }
     275             : 
     276           0 : static int scope_start(Unit *u) {
     277           0 :         Scope *s = SCOPE(u);
     278             :         int r;
     279             : 
     280           0 :         assert(s);
     281             : 
     282           0 :         if (s->state == SCOPE_FAILED)
     283           0 :                 return -EPERM;
     284             : 
     285             :         /* We can't fulfill this right now, please try again later */
     286           0 :         if (s->state == SCOPE_STOP_SIGTERM ||
     287           0 :             s->state == SCOPE_STOP_SIGKILL)
     288           0 :                 return -EAGAIN;
     289             : 
     290           0 :         assert(s->state == SCOPE_DEAD);
     291             : 
     292           0 :         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
     293           0 :                 return -ENOENT;
     294             : 
     295           0 :         (void) unit_realize_cgroup(u);
     296           0 :         (void) unit_reset_cpu_usage(u);
     297             : 
     298           0 :         r = unit_attach_pids_to_cgroup(u);
     299           0 :         if (r < 0) {
     300           0 :                 log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
     301           0 :                 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
     302           0 :                 return r;
     303             :         }
     304             : 
     305           0 :         s->result = SCOPE_SUCCESS;
     306             : 
     307           0 :         scope_set_state(s, SCOPE_RUNNING);
     308           0 :         return 1;
     309             : }
     310             : 
     311           0 : static int scope_stop(Unit *u) {
     312           0 :         Scope *s = SCOPE(u);
     313             : 
     314           0 :         assert(s);
     315             : 
     316           0 :         if (s->state == SCOPE_STOP_SIGTERM ||
     317           0 :             s->state == SCOPE_STOP_SIGKILL)
     318           0 :                 return 0;
     319             : 
     320           0 :         assert(s->state == SCOPE_RUNNING ||
     321             :                s->state == SCOPE_ABANDONED);
     322             : 
     323           0 :         scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
     324           0 :         return 1;
     325             : }
     326             : 
     327           0 : static void scope_reset_failed(Unit *u) {
     328           0 :         Scope *s = SCOPE(u);
     329             : 
     330           0 :         assert(s);
     331             : 
     332           0 :         if (s->state == SCOPE_FAILED)
     333           0 :                 scope_set_state(s, SCOPE_DEAD);
     334             : 
     335           0 :         s->result = SCOPE_SUCCESS;
     336           0 : }
     337             : 
     338           0 : static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
     339           0 :         return unit_kill_common(u, who, signo, -1, -1, error);
     340             : }
     341             : 
     342           0 : static int scope_get_timeout(Unit *u, uint64_t *timeout) {
     343           0 :         Scope *s = SCOPE(u);
     344             :         int r;
     345             : 
     346           0 :         if (!s->timer_event_source)
     347           0 :                 return 0;
     348             : 
     349           0 :         r = sd_event_source_get_time(s->timer_event_source, timeout);
     350           0 :         if (r < 0)
     351           0 :                 return r;
     352             : 
     353           0 :         return 1;
     354             : }
     355             : 
     356           0 : static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
     357           0 :         Scope *s = SCOPE(u);
     358             : 
     359           0 :         assert(s);
     360           0 :         assert(f);
     361           0 :         assert(fds);
     362             : 
     363           0 :         unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
     364           0 :         return 0;
     365             : }
     366             : 
     367           0 : static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
     368           0 :         Scope *s = SCOPE(u);
     369             : 
     370           0 :         assert(u);
     371           0 :         assert(key);
     372           0 :         assert(value);
     373           0 :         assert(fds);
     374             : 
     375           0 :         if (streq(key, "state")) {
     376             :                 ScopeState state;
     377             : 
     378           0 :                 state = scope_state_from_string(value);
     379           0 :                 if (state < 0)
     380           0 :                         log_unit_debug(u, "Failed to parse state value: %s", value);
     381             :                 else
     382           0 :                         s->deserialized_state = state;
     383             : 
     384             :         } else
     385           0 :                 log_unit_debug(u, "Unknown serialization key: %s", key);
     386             : 
     387           0 :         return 0;
     388             : }
     389             : 
     390           0 : static bool scope_check_gc(Unit *u) {
     391           0 :         assert(u);
     392             : 
     393             :         /* Never clean up scopes that still have a process around,
     394             :          * even if the scope is formally dead. */
     395             : 
     396           0 :         if (u->cgroup_path) {
     397             :                 int r;
     398             : 
     399           0 :                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
     400           0 :                 if (r <= 0)
     401           0 :                         return true;
     402             :         }
     403             : 
     404           0 :         return false;
     405             : }
     406             : 
     407           0 : static void scope_notify_cgroup_empty_event(Unit *u) {
     408           0 :         Scope *s = SCOPE(u);
     409           0 :         assert(u);
     410             : 
     411           0 :         log_unit_debug(u, "cgroup is empty");
     412             : 
     413           0 :         if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
     414           0 :                 scope_enter_dead(s, SCOPE_SUCCESS);
     415           0 : }
     416             : 
     417           0 : static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
     418             : 
     419             :         /* If we get a SIGCHLD event for one of the processes we were
     420             :            interested in, then we look for others to watch, under the
     421             :            assumption that we'll sooner or later get a SIGCHLD for
     422             :            them, as the original process we watched was probably the
     423             :            parent of them, and they are hence now our children. */
     424             : 
     425           0 :         unit_tidy_watch_pids(u, 0, 0);
     426           0 :         unit_watch_all_pids(u);
     427             : 
     428             :         /* If the PID set is empty now, then let's finish this off */
     429           0 :         if (set_isempty(u->pids))
     430           0 :                 scope_notify_cgroup_empty_event(u);
     431           0 : }
     432             : 
     433           0 : static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
     434           0 :         Scope *s = SCOPE(userdata);
     435             : 
     436           0 :         assert(s);
     437           0 :         assert(s->timer_event_source == source);
     438             : 
     439           0 :         switch (s->state) {
     440             : 
     441             :         case SCOPE_STOP_SIGTERM:
     442           0 :                 if (s->kill_context.send_sigkill) {
     443           0 :                         log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
     444           0 :                         scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
     445             :                 } else {
     446           0 :                         log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
     447           0 :                         scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
     448             :                 }
     449             : 
     450           0 :                 break;
     451             : 
     452             :         case SCOPE_STOP_SIGKILL:
     453           0 :                 log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
     454           0 :                 scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
     455           0 :                 break;
     456             : 
     457             :         default:
     458           0 :                 assert_not_reached("Timeout at wrong time.");
     459             :         }
     460             : 
     461           0 :         return 0;
     462             : }
     463             : 
     464           0 : int scope_abandon(Scope *s) {
     465           0 :         assert(s);
     466             : 
     467           0 :         if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
     468           0 :                 return -ESTALE;
     469             : 
     470           0 :         free(s->controller);
     471           0 :         s->controller = NULL;
     472             : 
     473             :         /* The client is no longer watching the remaining processes,
     474             :          * so let's step in here, under the assumption that the
     475             :          * remaining processes will be sooner or later reassigned to
     476             :          * us as parent. */
     477             : 
     478           0 :         unit_tidy_watch_pids(UNIT(s), 0, 0);
     479           0 :         unit_watch_all_pids(UNIT(s));
     480             : 
     481             :         /* If the PID set is empty now, then let's finish this off */
     482           0 :         if (set_isempty(UNIT(s)->pids))
     483           0 :                 scope_notify_cgroup_empty_event(UNIT(s));
     484             :         else
     485           0 :                 scope_set_state(s, SCOPE_ABANDONED);
     486             : 
     487           0 :         return 0;
     488             : }
     489             : 
     490           0 : _pure_ static UnitActiveState scope_active_state(Unit *u) {
     491           0 :         assert(u);
     492             : 
     493           0 :         return state_translation_table[SCOPE(u)->state];
     494             : }
     495             : 
     496           0 : _pure_ static const char *scope_sub_state_to_string(Unit *u) {
     497           0 :         assert(u);
     498             : 
     499           0 :         return scope_state_to_string(SCOPE(u)->state);
     500             : }
     501             : 
     502             : static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
     503             :         [SCOPE_DEAD] = "dead",
     504             :         [SCOPE_RUNNING] = "running",
     505             :         [SCOPE_ABANDONED] = "abandoned",
     506             :         [SCOPE_STOP_SIGTERM] = "stop-sigterm",
     507             :         [SCOPE_STOP_SIGKILL] = "stop-sigkill",
     508             :         [SCOPE_FAILED] = "failed",
     509             : };
     510             : 
     511          16 : DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
     512             : 
     513             : static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
     514             :         [SCOPE_SUCCESS] = "success",
     515             :         [SCOPE_FAILURE_RESOURCES] = "resources",
     516             :         [SCOPE_FAILURE_TIMEOUT] = "timeout",
     517             : };
     518             : 
     519          10 : DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
     520             : 
     521             : const UnitVTable scope_vtable = {
     522             :         .object_size = sizeof(Scope),
     523             :         .cgroup_context_offset = offsetof(Scope, cgroup_context),
     524             :         .kill_context_offset = offsetof(Scope, kill_context),
     525             : 
     526             :         .sections =
     527             :                 "Unit\0"
     528             :                 "Scope\0"
     529             :                 "Install\0",
     530             :         .private_section = "Scope",
     531             : 
     532             :         .no_alias = true,
     533             :         .no_instances = true,
     534             : 
     535             :         .init = scope_init,
     536             :         .load = scope_load,
     537             :         .done = scope_done,
     538             : 
     539             :         .coldplug = scope_coldplug,
     540             : 
     541             :         .dump = scope_dump,
     542             : 
     543             :         .start = scope_start,
     544             :         .stop = scope_stop,
     545             : 
     546             :         .kill = scope_kill,
     547             : 
     548             :         .get_timeout = scope_get_timeout,
     549             : 
     550             :         .serialize = scope_serialize,
     551             :         .deserialize_item = scope_deserialize_item,
     552             : 
     553             :         .active_state = scope_active_state,
     554             :         .sub_state_to_string = scope_sub_state_to_string,
     555             : 
     556             :         .check_gc = scope_check_gc,
     557             : 
     558             :         .sigchld_event = scope_sigchld_event,
     559             : 
     560             :         .reset_failed = scope_reset_failed,
     561             : 
     562             :         .notify_cgroup_empty = scope_notify_cgroup_empty_event,
     563             : 
     564             :         .bus_interface = "org.freedesktop.systemd1.Scope",
     565             :         .bus_vtable = bus_scope_vtable,
     566             :         .bus_set_property = bus_scope_set_property,
     567             :         .bus_commit_properties = bus_scope_commit_properties,
     568             : 
     569             :         .can_transient = true
     570             : };

Generated by: LCOV version 1.11