LCOV - code coverage report
Current view: top level - machine - machine.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 3 366 0.8 %
Date: 2019-08-22 15:41:25 Functions: 6 24 25.0 %

          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          10 : 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          10 : 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           8 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);

Generated by: LCOV version 1.14