LCOV - code coverage report
Current view: top level - machine - machine.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 3 366 0.8 %
Date: 2019-08-23 13:36:53 Functions: 6 24 25.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 12 350 3.4 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <string.h>
       5                 :            : #include <unistd.h>
       6                 :            : #include <sys/stat.h>
       7                 :            : 
       8                 :            : #include "sd-messages.h"
       9                 :            : 
      10                 :            : #include "alloc-util.h"
      11                 :            : #include "bus-error.h"
      12                 :            : #include "bus-util.h"
      13                 :            : #include "env-file.h"
      14                 :            : #include "errno-util.h"
      15                 :            : #include "escape.h"
      16                 :            : #include "extract-word.h"
      17                 :            : #include "fd-util.h"
      18                 :            : #include "fileio.h"
      19                 :            : #include "format-util.h"
      20                 :            : #include "hashmap.h"
      21                 :            : #include "machine-dbus.h"
      22                 :            : #include "machine.h"
      23                 :            : #include "mkdir.h"
      24                 :            : #include "parse-util.h"
      25                 :            : #include "path-util.h"
      26                 :            : #include "process-util.h"
      27                 :            : #include "serialize.h"
      28                 :            : #include "special.h"
      29                 :            : #include "stdio-util.h"
      30                 :            : #include "string-table.h"
      31                 :            : #include "terminal-util.h"
      32                 :            : #include "tmpfile-util.h"
      33                 :            : #include "unit-name.h"
      34                 :            : #include "user-util.h"
      35                 :            : #include "util.h"
      36                 :            : 
      37                 :          0 : Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
      38                 :            :         Machine *m;
      39                 :            : 
      40         [ #  # ]:          0 :         assert(manager);
      41         [ #  # ]:          0 :         assert(class < _MACHINE_CLASS_MAX);
      42         [ #  # ]:          0 :         assert(name);
      43                 :            : 
      44                 :            :         /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
      45                 :            :          * means as much as "we don't know yet", and that we'll figure
      46                 :            :          * it out later when loading the state file. */
      47                 :            : 
      48                 :          0 :         m = new0(Machine, 1);
      49         [ #  # ]:          0 :         if (!m)
      50                 :          0 :                 return NULL;
      51                 :            : 
      52                 :          0 :         m->name = strdup(name);
      53         [ #  # ]:          0 :         if (!m->name)
      54                 :          0 :                 goto fail;
      55                 :            : 
      56         [ #  # ]:          0 :         if (class != MACHINE_HOST) {
      57                 :          0 :                 m->state_file = path_join("/run/systemd/machines", m->name);
      58         [ #  # ]:          0 :                 if (!m->state_file)
      59                 :          0 :                         goto fail;
      60                 :            :         }
      61                 :            : 
      62                 :          0 :         m->class = class;
      63                 :            : 
      64         [ #  # ]:          0 :         if (hashmap_put(manager->machines, m->name, m) < 0)
      65                 :          0 :                 goto fail;
      66                 :            : 
      67                 :          0 :         m->manager = manager;
      68                 :            : 
      69                 :          0 :         return m;
      70                 :            : 
      71                 :          0 : fail:
      72                 :          0 :         free(m->state_file);
      73                 :          0 :         free(m->name);
      74                 :          0 :         return mfree(m);
      75                 :            : }
      76                 :            : 
      77                 :          0 : Machine* machine_free(Machine *m) {
      78         [ #  # ]:          0 :         if (!m)
      79                 :          0 :                 return NULL;
      80                 :            : 
      81         [ #  # ]:          0 :         while (m->operations)
      82                 :          0 :                 operation_free(m->operations);
      83                 :            : 
      84         [ #  # ]:          0 :         if (m->in_gc_queue)
      85   [ #  #  #  #  :          0 :                 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
             #  #  #  # ]
      86                 :            : 
      87                 :          0 :         machine_release_unit(m);
      88                 :            : 
      89                 :          0 :         free(m->scope_job);
      90                 :            : 
      91                 :          0 :         (void) hashmap_remove(m->manager->machines, m->name);
      92                 :            : 
      93         [ #  # ]:          0 :         if (m->manager->host_machine == m)
      94                 :          0 :                 m->manager->host_machine = NULL;
      95                 :            : 
      96         [ #  # ]:          0 :         if (m->leader > 0)
      97                 :          0 :                 (void) hashmap_remove_value(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
      98                 :            : 
      99                 :          0 :         sd_bus_message_unref(m->create_message);
     100                 :            : 
     101                 :          0 :         free(m->name);
     102                 :          0 :         free(m->state_file);
     103                 :          0 :         free(m->service);
     104                 :          0 :         free(m->root_directory);
     105                 :          0 :         free(m->netif);
     106                 :          0 :         return mfree(m);
     107                 :            : }
     108                 :            : 
     109                 :          0 : int machine_save(Machine *m) {
     110                 :          0 :         _cleanup_free_ char *temp_path = NULL;
     111                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     112                 :            :         int r;
     113                 :            : 
     114         [ #  # ]:          0 :         assert(m);
     115                 :            : 
     116         [ #  # ]:          0 :         if (!m->state_file)
     117                 :          0 :                 return 0;
     118                 :            : 
     119         [ #  # ]:          0 :         if (!m->started)
     120                 :          0 :                 return 0;
     121                 :            : 
     122                 :          0 :         r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, MKDIR_WARN_MODE);
     123         [ #  # ]:          0 :         if (r < 0)
     124                 :          0 :                 goto fail;
     125                 :            : 
     126                 :          0 :         r = fopen_temporary(m->state_file, &f, &temp_path);
     127         [ #  # ]:          0 :         if (r < 0)
     128                 :          0 :                 goto fail;
     129                 :            : 
     130                 :          0 :         (void) fchmod(fileno(f), 0644);
     131                 :            : 
     132                 :          0 :         fprintf(f,
     133                 :            :                 "# This is private data. Do not parse.\n"
     134                 :            :                 "NAME=%s\n",
     135                 :            :                 m->name);
     136                 :            : 
     137         [ #  # ]:          0 :         if (m->unit) {
     138         [ #  # ]:          0 :                 _cleanup_free_ char *escaped;
     139                 :            : 
     140                 :          0 :                 escaped = cescape(m->unit);
     141         [ #  # ]:          0 :                 if (!escaped) {
     142                 :          0 :                         r = -ENOMEM;
     143                 :          0 :                         goto fail;
     144                 :            :                 }
     145                 :            : 
     146                 :          0 :                 fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
     147                 :            :         }
     148                 :            : 
     149         [ #  # ]:          0 :         if (m->scope_job)
     150                 :          0 :                 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
     151                 :            : 
     152         [ #  # ]:          0 :         if (m->service) {
     153         [ #  # ]:          0 :                 _cleanup_free_ char *escaped;
     154                 :            : 
     155                 :          0 :                 escaped = cescape(m->service);
     156         [ #  # ]:          0 :                 if (!escaped) {
     157                 :          0 :                         r = -ENOMEM;
     158                 :          0 :                         goto fail;
     159                 :            :                 }
     160                 :          0 :                 fprintf(f, "SERVICE=%s\n", escaped);
     161                 :            :         }
     162                 :            : 
     163         [ #  # ]:          0 :         if (m->root_directory) {
     164         [ #  # ]:          0 :                 _cleanup_free_ char *escaped;
     165                 :            : 
     166                 :          0 :                 escaped = cescape(m->root_directory);
     167         [ #  # ]:          0 :                 if (!escaped) {
     168                 :          0 :                         r = -ENOMEM;
     169                 :          0 :                         goto fail;
     170                 :            :                 }
     171                 :          0 :                 fprintf(f, "ROOT=%s\n", escaped);
     172                 :            :         }
     173                 :            : 
     174         [ #  # ]:          0 :         if (!sd_id128_is_null(m->id))
     175                 :          0 :                 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
     176                 :            : 
     177         [ #  # ]:          0 :         if (m->leader != 0)
     178                 :          0 :                 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
     179                 :            : 
     180         [ #  # ]:          0 :         if (m->class != _MACHINE_CLASS_INVALID)
     181                 :          0 :                 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
     182                 :            : 
     183         [ #  # ]:          0 :         if (dual_timestamp_is_set(&m->timestamp))
     184                 :          0 :                 fprintf(f,
     185                 :            :                         "REALTIME="USEC_FMT"\n"
     186                 :            :                         "MONOTONIC="USEC_FMT"\n",
     187                 :            :                         m->timestamp.realtime,
     188                 :            :                         m->timestamp.monotonic);
     189                 :            : 
     190         [ #  # ]:          0 :         if (m->n_netif > 0) {
     191                 :            :                 size_t i;
     192                 :            : 
     193                 :          0 :                 fputs("NETIF=", f);
     194                 :            : 
     195         [ #  # ]:          0 :                 for (i = 0; i < m->n_netif; i++) {
     196         [ #  # ]:          0 :                         if (i != 0)
     197                 :          0 :                                 fputc(' ', f);
     198                 :            : 
     199                 :          0 :                         fprintf(f, "%i", m->netif[i]);
     200                 :            :                 }
     201                 :            : 
     202                 :          0 :                 fputc('\n', f);
     203                 :            :         }
     204                 :            : 
     205                 :          0 :         r = fflush_and_check(f);
     206         [ #  # ]:          0 :         if (r < 0)
     207                 :          0 :                 goto fail;
     208                 :            : 
     209         [ #  # ]:          0 :         if (rename(temp_path, m->state_file) < 0) {
     210                 :          0 :                 r = -errno;
     211                 :          0 :                 goto fail;
     212                 :            :         }
     213                 :            : 
     214         [ #  # ]:          0 :         if (m->unit) {
     215                 :            :                 char *sl;
     216                 :            : 
     217                 :            :                 /* Create a symlink from the unit name to the machine
     218                 :            :                  * name, so that we can quickly find the machine for
     219                 :            :                  * each given unit. Ignore error. */
     220   [ #  #  #  #  :          0 :                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
          #  #  #  #  #  
                #  #  # ]
     221                 :          0 :                 (void) symlink(m->name, sl);
     222                 :            :         }
     223                 :            : 
     224                 :          0 :         return 0;
     225                 :            : 
     226                 :          0 : fail:
     227                 :          0 :         (void) unlink(m->state_file);
     228                 :            : 
     229         [ #  # ]:          0 :         if (temp_path)
     230                 :          0 :                 (void) unlink(temp_path);
     231                 :            : 
     232         [ #  # ]:          0 :         return log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
     233                 :            : }
     234                 :            : 
     235                 :          0 : static void machine_unlink(Machine *m) {
     236         [ #  # ]:          0 :         assert(m);
     237                 :            : 
     238         [ #  # ]:          0 :         if (m->unit) {
     239                 :            :                 char *sl;
     240                 :            : 
     241   [ #  #  #  #  :          0 :                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
          #  #  #  #  #  
                #  #  # ]
     242                 :          0 :                 (void) unlink(sl);
     243                 :            :         }
     244                 :            : 
     245         [ #  # ]:          0 :         if (m->state_file)
     246                 :          0 :                 (void) unlink(m->state_file);
     247                 :          0 : }
     248                 :            : 
     249                 :          0 : int machine_load(Machine *m) {
     250                 :          0 :         _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
     251                 :            :         int r;
     252                 :            : 
     253         [ #  # ]:          0 :         assert(m);
     254                 :            : 
     255         [ #  # ]:          0 :         if (!m->state_file)
     256                 :          0 :                 return 0;
     257                 :            : 
     258                 :          0 :         r = parse_env_file(NULL, m->state_file,
     259                 :            :                            "SCOPE",     &m->unit,
     260                 :            :                            "SCOPE_JOB", &m->scope_job,
     261                 :            :                            "SERVICE",   &m->service,
     262                 :            :                            "ROOT",      &m->root_directory,
     263                 :            :                            "ID",        &id,
     264                 :            :                            "LEADER",    &leader,
     265                 :            :                            "CLASS",     &class,
     266                 :            :                            "REALTIME",  &realtime,
     267                 :            :                            "MONOTONIC", &monotonic,
     268                 :            :                            "NETIF",     &netif);
     269         [ #  # ]:          0 :         if (r < 0) {
     270         [ #  # ]:          0 :                 if (r == -ENOENT)
     271                 :          0 :                         return 0;
     272                 :            : 
     273         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
     274                 :            :         }
     275                 :            : 
     276         [ #  # ]:          0 :         if (id)
     277                 :          0 :                 sd_id128_from_string(id, &m->id);
     278                 :            : 
     279         [ #  # ]:          0 :         if (leader)
     280                 :          0 :                 parse_pid(leader, &m->leader);
     281                 :            : 
     282         [ #  # ]:          0 :         if (class) {
     283                 :            :                 MachineClass c;
     284                 :            : 
     285                 :          0 :                 c = machine_class_from_string(class);
     286         [ #  # ]:          0 :                 if (c >= 0)
     287                 :          0 :                         m->class = c;
     288                 :            :         }
     289                 :            : 
     290         [ #  # ]:          0 :         if (realtime)
     291                 :          0 :                 (void) deserialize_usec(realtime, &m->timestamp.realtime);
     292         [ #  # ]:          0 :         if (monotonic)
     293                 :          0 :                 (void) deserialize_usec(monotonic, &m->timestamp.monotonic);
     294                 :            : 
     295         [ #  # ]:          0 :         if (netif) {
     296                 :          0 :                 size_t allocated = 0, nr = 0;
     297                 :            :                 const char *p;
     298                 :          0 :                 int *ni = NULL;
     299                 :            : 
     300                 :          0 :                 p = netif;
     301                 :          0 :                 for (;;) {
     302   [ #  #  #  # ]:          0 :                         _cleanup_free_ char *word = NULL;
     303                 :            :                         int ifi;
     304                 :            : 
     305                 :          0 :                         r = extract_first_word(&p, &word, NULL, 0);
     306         [ #  # ]:          0 :                         if (r == 0)
     307                 :          0 :                                 break;
     308         [ #  # ]:          0 :                         if (r == -ENOMEM)
     309                 :          0 :                                 return log_oom();
     310         [ #  # ]:          0 :                         if (r < 0) {
     311         [ #  # ]:          0 :                                 log_warning_errno(r, "Failed to parse NETIF: %s", netif);
     312                 :          0 :                                 break;
     313                 :            :                         }
     314                 :            : 
     315         [ #  # ]:          0 :                         if (parse_ifindex(word, &ifi) < 0)
     316                 :          0 :                                 continue;
     317                 :            : 
     318         [ #  # ]:          0 :                         if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
     319                 :          0 :                                 free(ni);
     320                 :          0 :                                 return log_oom();
     321                 :            :                         }
     322                 :            : 
     323                 :          0 :                         ni[nr++] = ifi;
     324                 :            :                 }
     325                 :            : 
     326                 :          0 :                 free(m->netif);
     327                 :          0 :                 m->netif = ni;
     328                 :          0 :                 m->n_netif = nr;
     329                 :            :         }
     330                 :            : 
     331                 :          0 :         return r;
     332                 :            : }
     333                 :            : 
     334                 :          0 : static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
     335         [ #  # ]:          0 :         assert(m);
     336         [ #  # ]:          0 :         assert(m->class != MACHINE_HOST);
     337                 :            : 
     338         [ #  # ]:          0 :         if (!m->unit) {
     339   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *escaped = NULL, *scope = NULL;
     340                 :          0 :                 char *description, *job = NULL;
     341                 :            :                 int r;
     342                 :            : 
     343                 :          0 :                 escaped = unit_name_escape(m->name);
     344         [ #  # ]:          0 :                 if (!escaped)
     345                 :          0 :                         return log_oom();
     346                 :            : 
     347                 :          0 :                 scope = strjoin("machine-", escaped, ".scope");
     348         [ #  # ]:          0 :                 if (!scope)
     349                 :          0 :                         return log_oom();
     350                 :            : 
     351   [ #  #  #  #  :          0 :                 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     352                 :            : 
     353                 :          0 :                 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
     354         [ #  # ]:          0 :                 if (r < 0)
     355         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r));
     356                 :            : 
     357                 :          0 :                 m->unit = TAKE_PTR(scope);
     358                 :          0 :                 free_and_replace(m->scope_job, job);
     359                 :            :         }
     360                 :            : 
     361         [ #  # ]:          0 :         if (m->unit)
     362                 :          0 :                 hashmap_put(m->manager->machine_units, m->unit, m);
     363                 :            : 
     364                 :          0 :         return 0;
     365                 :            : }
     366                 :            : 
     367                 :          0 : int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
     368                 :            :         int r;
     369                 :            : 
     370         [ #  # ]:          0 :         assert(m);
     371                 :            : 
     372   [ #  #  #  # ]:          0 :         if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
     373                 :          0 :                 return -EOPNOTSUPP;
     374                 :            : 
     375         [ #  # ]:          0 :         if (m->started)
     376                 :          0 :                 return 0;
     377                 :            : 
     378                 :          0 :         r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
     379         [ #  # ]:          0 :         if (r < 0)
     380                 :          0 :                 return r;
     381                 :            : 
     382                 :            :         /* Create cgroup */
     383                 :          0 :         r = machine_start_scope(m, properties, error);
     384         [ #  # ]:          0 :         if (r < 0)
     385                 :          0 :                 return r;
     386                 :            : 
     387                 :          0 :         log_struct(LOG_INFO,
     388                 :            :                    "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR,
     389                 :            :                    "NAME=%s", m->name,
     390                 :            :                    "LEADER="PID_FMT, m->leader,
     391                 :            :                    LOG_MESSAGE("New machine %s.", m->name));
     392                 :            : 
     393         [ #  # ]:          0 :         if (!dual_timestamp_is_set(&m->timestamp))
     394                 :          0 :                 dual_timestamp_get(&m->timestamp);
     395                 :            : 
     396                 :          0 :         m->started = true;
     397                 :            : 
     398                 :            :         /* Save new machine data */
     399                 :          0 :         machine_save(m);
     400                 :            : 
     401                 :          0 :         machine_send_signal(m, true);
     402                 :          0 :         (void) manager_enqueue_nscd_cache_flush(m->manager);
     403                 :            : 
     404                 :          0 :         return 0;
     405                 :            : }
     406                 :            : 
     407                 :          0 : static int machine_stop_scope(Machine *m) {
     408                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     409                 :          0 :         char *job = NULL;
     410                 :            :         int r, q;
     411                 :            : 
     412         [ #  # ]:          0 :         assert(m);
     413         [ #  # ]:          0 :         assert(m->class != MACHINE_HOST);
     414                 :            : 
     415         [ #  # ]:          0 :         if (!m->unit)
     416                 :          0 :                 return 0;
     417                 :            : 
     418                 :          0 :         r = manager_stop_unit(m->manager, m->unit, &error, &job);
     419         [ #  # ]:          0 :         if (r < 0) {
     420         [ #  # ]:          0 :                 log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
     421                 :          0 :                 sd_bus_error_free(&error);
     422                 :            :         } else
     423                 :          0 :                 free_and_replace(m->scope_job, job);
     424                 :            : 
     425                 :          0 :         q = manager_unref_unit(m->manager, m->unit, &error);
     426         [ #  # ]:          0 :         if (q < 0)
     427         [ #  # ]:          0 :                 log_warning_errno(q, "Failed to drop reference to machine scope, ignoring: %s", bus_error_message(&error, r));
     428                 :            : 
     429                 :          0 :         return r;
     430                 :            : }
     431                 :            : 
     432                 :          0 : int machine_stop(Machine *m) {
     433                 :            :         int r;
     434         [ #  # ]:          0 :         assert(m);
     435                 :            : 
     436   [ #  #  #  # ]:          0 :         if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
     437                 :          0 :                 return -EOPNOTSUPP;
     438                 :            : 
     439                 :          0 :         r = machine_stop_scope(m);
     440                 :            : 
     441                 :          0 :         m->stopping = true;
     442                 :            : 
     443                 :          0 :         machine_save(m);
     444                 :          0 :         (void) manager_enqueue_nscd_cache_flush(m->manager);
     445                 :            : 
     446                 :          0 :         return r;
     447                 :            : }
     448                 :            : 
     449                 :          0 : int machine_finalize(Machine *m) {
     450         [ #  # ]:          0 :         assert(m);
     451                 :            : 
     452         [ #  # ]:          0 :         if (m->started)
     453                 :          0 :                 log_struct(LOG_INFO,
     454                 :            :                            "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR,
     455                 :            :                            "NAME=%s", m->name,
     456                 :            :                            "LEADER="PID_FMT, m->leader,
     457                 :            :                            LOG_MESSAGE("Machine %s terminated.", m->name));
     458                 :            : 
     459                 :          0 :         machine_unlink(m);
     460                 :          0 :         machine_add_to_gc_queue(m);
     461                 :            : 
     462         [ #  # ]:          0 :         if (m->started) {
     463                 :          0 :                 machine_send_signal(m, false);
     464                 :          0 :                 m->started = false;
     465                 :            :         }
     466                 :            : 
     467                 :          0 :         return 0;
     468                 :            : }
     469                 :            : 
     470                 :          0 : bool machine_may_gc(Machine *m, bool drop_not_started) {
     471         [ #  # ]:          0 :         assert(m);
     472                 :            : 
     473         [ #  # ]:          0 :         if (m->class == MACHINE_HOST)
     474                 :          0 :                 return false;
     475                 :            : 
     476   [ #  #  #  # ]:          0 :         if (drop_not_started && !m->started)
     477                 :          0 :                 return true;
     478                 :            : 
     479   [ #  #  #  # ]:          0 :         if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
     480                 :          0 :                 return false;
     481                 :            : 
     482   [ #  #  #  # ]:          0 :         if (m->unit && manager_unit_is_active(m->manager, m->unit))
     483                 :          0 :                 return false;
     484                 :            : 
     485                 :          0 :         return true;
     486                 :            : }
     487                 :            : 
     488                 :          0 : void machine_add_to_gc_queue(Machine *m) {
     489         [ #  # ]:          0 :         assert(m);
     490                 :            : 
     491         [ #  # ]:          0 :         if (m->in_gc_queue)
     492                 :          0 :                 return;
     493                 :            : 
     494   [ #  #  #  # ]:          0 :         LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
     495                 :          0 :         m->in_gc_queue = true;
     496                 :            : }
     497                 :            : 
     498                 :          0 : MachineState machine_get_state(Machine *s) {
     499         [ #  # ]:          0 :         assert(s);
     500                 :            : 
     501         [ #  # ]:          0 :         if (s->class == MACHINE_HOST)
     502                 :          0 :                 return MACHINE_RUNNING;
     503                 :            : 
     504         [ #  # ]:          0 :         if (s->stopping)
     505                 :          0 :                 return MACHINE_CLOSING;
     506                 :            : 
     507         [ #  # ]:          0 :         if (s->scope_job)
     508                 :          0 :                 return MACHINE_OPENING;
     509                 :            : 
     510                 :          0 :         return MACHINE_RUNNING;
     511                 :            : }
     512                 :            : 
     513                 :          0 : int machine_kill(Machine *m, KillWho who, int signo) {
     514         [ #  # ]:          0 :         assert(m);
     515                 :            : 
     516   [ #  #  #  # ]:          0 :         if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
     517                 :          0 :                 return -EOPNOTSUPP;
     518                 :            : 
     519         [ #  # ]:          0 :         if (!m->unit)
     520                 :          0 :                 return -ESRCH;
     521                 :            : 
     522         [ #  # ]:          0 :         if (who == KILL_LEADER) {
     523                 :            :                 /* If we shall simply kill the leader, do so directly */
     524                 :            : 
     525         [ #  # ]:          0 :                 if (kill(m->leader, signo) < 0)
     526                 :          0 :                         return -errno;
     527                 :            : 
     528                 :          0 :                 return 0;
     529                 :            :         }
     530                 :            : 
     531                 :            :         /* Otherwise, make PID 1 do it for us, for the entire cgroup */
     532                 :          0 :         return manager_kill_unit(m->manager, m->unit, signo, NULL);
     533                 :            : }
     534                 :            : 
     535                 :          0 : int machine_openpt(Machine *m, int flags, char **ret_slave) {
     536         [ #  # ]:          0 :         assert(m);
     537                 :            : 
     538      [ #  #  # ]:          0 :         switch (m->class) {
     539                 :            : 
     540                 :          0 :         case MACHINE_HOST:
     541                 :            : 
     542                 :          0 :                 return openpt_allocate(flags, ret_slave);
     543                 :            : 
     544                 :          0 :         case MACHINE_CONTAINER:
     545         [ #  # ]:          0 :                 if (m->leader <= 0)
     546                 :          0 :                         return -EINVAL;
     547                 :            : 
     548                 :          0 :                 return openpt_allocate_in_namespace(m->leader, flags, ret_slave);
     549                 :            : 
     550                 :          0 :         default:
     551                 :          0 :                 return -EOPNOTSUPP;
     552                 :            :         }
     553                 :            : }
     554                 :            : 
     555                 :          0 : int machine_open_terminal(Machine *m, const char *path, int mode) {
     556         [ #  # ]:          0 :         assert(m);
     557                 :            : 
     558      [ #  #  # ]:          0 :         switch (m->class) {
     559                 :            : 
     560                 :          0 :         case MACHINE_HOST:
     561                 :          0 :                 return open_terminal(path, mode);
     562                 :            : 
     563                 :          0 :         case MACHINE_CONTAINER:
     564         [ #  # ]:          0 :                 if (m->leader <= 0)
     565                 :          0 :                         return -EINVAL;
     566                 :            : 
     567                 :          0 :                 return open_terminal_in_namespace(m->leader, path, mode);
     568                 :            : 
     569                 :          0 :         default:
     570                 :          0 :                 return -EOPNOTSUPP;
     571                 :            :         }
     572                 :            : }
     573                 :            : 
     574                 :          0 : void machine_release_unit(Machine *m) {
     575         [ #  # ]:          0 :         assert(m);
     576                 :            : 
     577         [ #  # ]:          0 :         if (!m->unit)
     578                 :          0 :                 return;
     579                 :            : 
     580                 :          0 :         (void) hashmap_remove(m->manager->machine_units, m->unit);
     581                 :          0 :         m->unit = mfree(m->unit);
     582                 :            : }
     583                 :            : 
     584                 :          0 : int machine_get_uid_shift(Machine *m, uid_t *ret) {
     585                 :            :         char p[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
     586                 :            :         uid_t uid_base, uid_shift, uid_range;
     587                 :            :         gid_t gid_base, gid_shift, gid_range;
     588                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     589                 :            :         int k, r;
     590                 :            : 
     591         [ #  # ]:          0 :         assert(m);
     592         [ #  # ]:          0 :         assert(ret);
     593                 :            : 
     594                 :            :         /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
     595                 :            :          * mappings. In most cases setups should be simple like this, and administrators should only care about the
     596                 :            :          * basic offset a container has relative to the host. This is what this function exposes.
     597                 :            :          *
     598                 :            :          * If we encounter any more complex mappings we politely refuse this with ENXIO. */
     599                 :            : 
     600         [ #  # ]:          0 :         if (m->class == MACHINE_HOST) {
     601                 :          0 :                 *ret = 0;
     602                 :          0 :                 return 0;
     603                 :            :         }
     604                 :            : 
     605         [ #  # ]:          0 :         if (m->class != MACHINE_CONTAINER)
     606                 :          0 :                 return -EOPNOTSUPP;
     607                 :            : 
     608         [ #  # ]:          0 :         xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader);
     609                 :          0 :         f = fopen(p, "re");
     610         [ #  # ]:          0 :         if (!f) {
     611         [ #  # ]:          0 :                 if (errno == ENOENT) {
     612                 :            :                         /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
     613                 :          0 :                         *ret = 0;
     614                 :          0 :                         return 0;
     615                 :            :                 }
     616                 :            : 
     617                 :          0 :                 return -errno;
     618                 :            :         }
     619                 :            : 
     620                 :            :         /* Read the first line. There's at least one. */
     621                 :          0 :         errno = 0;
     622                 :          0 :         k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
     623         [ #  # ]:          0 :         if (k != 3) {
     624         [ #  # ]:          0 :                 if (ferror(f))
     625                 :          0 :                         return errno_or_else(EIO);
     626                 :            : 
     627                 :          0 :                 return -EBADMSG;
     628                 :            :         }
     629                 :            : 
     630                 :            :         /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
     631         [ #  # ]:          0 :         if (uid_base != 0)
     632                 :          0 :                 return -ENXIO;
     633                 :            :         /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
     634         [ #  # ]:          0 :         if (uid_range < UID_NOBODY)
     635                 :          0 :                 return -ENXIO;
     636                 :            : 
     637                 :            :         /* If there's more than one line, then we don't support this mapping. */
     638                 :          0 :         r = safe_fgetc(f, NULL);
     639         [ #  # ]:          0 :         if (r < 0)
     640                 :          0 :                 return r;
     641         [ #  # ]:          0 :         if (r != 0) /* Insist on EOF */
     642                 :          0 :                 return -ENXIO;
     643                 :            : 
     644                 :          0 :         fclose(f);
     645                 :            : 
     646         [ #  # ]:          0 :         xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader);
     647                 :          0 :         f = fopen(p, "re");
     648         [ #  # ]:          0 :         if (!f)
     649                 :          0 :                 return -errno;
     650                 :            : 
     651                 :            :         /* Read the first line. There's at least one. */
     652                 :          0 :         errno = 0;
     653                 :          0 :         k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
     654         [ #  # ]:          0 :         if (k != 3) {
     655         [ #  # ]:          0 :                 if (ferror(f))
     656                 :          0 :                         return errno_or_else(EIO);
     657                 :            : 
     658                 :          0 :                 return -EBADMSG;
     659                 :            :         }
     660                 :            : 
     661                 :            :         /* If there's more than one line, then we don't support this file. */
     662                 :          0 :         r = safe_fgetc(f, NULL);
     663         [ #  # ]:          0 :         if (r < 0)
     664                 :          0 :                 return r;
     665         [ #  # ]:          0 :         if (r != 0) /* Insist on EOF */
     666                 :          0 :                 return -ENXIO;
     667                 :            : 
     668                 :            :         /* If the UID and GID mapping doesn't match, we don't support this mapping. */
     669         [ #  # ]:          0 :         if (uid_base != (uid_t) gid_base)
     670                 :          0 :                 return -ENXIO;
     671         [ #  # ]:          0 :         if (uid_shift != (uid_t) gid_shift)
     672                 :          0 :                 return -ENXIO;
     673         [ #  # ]:          0 :         if (uid_range != (uid_t) gid_range)
     674                 :          0 :                 return -ENXIO;
     675                 :            : 
     676                 :          0 :         *ret = uid_shift;
     677                 :          0 :         return 0;
     678                 :            : }
     679                 :            : 
     680                 :            : static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
     681                 :            :         [MACHINE_CONTAINER] = "container",
     682                 :            :         [MACHINE_VM] = "vm",
     683                 :            :         [MACHINE_HOST] = "host",
     684                 :            : };
     685                 :            : 
     686   [ +  +  +  + ]:         40 : DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
     687                 :            : 
     688                 :            : static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
     689                 :            :         [MACHINE_OPENING] = "opening",
     690                 :            :         [MACHINE_RUNNING] = "running",
     691                 :            :         [MACHINE_CLOSING] = "closing"
     692                 :            : };
     693                 :            : 
     694   [ +  +  +  + ]:         40 : DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
     695                 :            : 
     696                 :            : static const char* const kill_who_table[_KILL_WHO_MAX] = {
     697                 :            :         [KILL_LEADER] = "leader",
     698                 :            :         [KILL_ALL] = "all"
     699                 :            : };
     700                 :            : 
     701   [ +  +  +  + ]:         32 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);

Generated by: LCOV version 1.14