LCOV - code coverage report
Current view: top level - shared - exit-status.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 33 50 66.0 %
Date: 2019-08-22 15:41:25 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <signal.h>
       4             : #include <stdlib.h>
       5             : #include <sysexits.h>
       6             : 
       7             : #include "exit-status.h"
       8             : #include "macro.h"
       9             : #include "parse-util.h"
      10             : #include "set.h"
      11             : #include "string-util.h"
      12             : 
      13             : const ExitStatusMapping exit_status_mappings[256] = {
      14             :         /* Exit status ranges:
      15             :          *
      16             :          *   0…1   │ ISO C, EXIT_SUCCESS + EXIT_FAILURE
      17             :          *   2…7   │ LSB exit codes for init scripts
      18             :          *   8…63  │ (Currently unmapped)
      19             :          *  64…78  │ BSD defined exit codes
      20             :          *  79…199 │ (Currently unmapped)
      21             :          * 200…242 │ systemd's private error codes (might be extended to 254 in future development)
      22             :          * 243…254 │ (Currently unmapped, but see above)
      23             :          *
      24             :          *   255   │ EXIT_EXCEPTION (We use this to propagate exit-by-signal events. It's frequently used by others apps (like bash)
      25             :          *         │ to indicate exit reason that cannot really be expressed in a single exit status value — such as a propagated
      26             :          *         │ signal or such, and we follow that logic here.)
      27             :          */
      28             : 
      29             :         [EXIT_SUCCESS] =                 { "SUCCESS",                 EXIT_STATUS_LIBC },
      30             :         [EXIT_FAILURE] =                 { "FAILURE",                 EXIT_STATUS_LIBC },
      31             : 
      32             :         [EXIT_CHDIR] =                   { "CHDIR",                   EXIT_STATUS_SYSTEMD },
      33             :         [EXIT_NICE] =                    { "NICE",                    EXIT_STATUS_SYSTEMD },
      34             :         [EXIT_FDS] =                     { "FDS",                     EXIT_STATUS_SYSTEMD },
      35             :         [EXIT_EXEC] =                    { "EXEC",                    EXIT_STATUS_SYSTEMD },
      36             :         [EXIT_MEMORY] =                  { "MEMORY",                  EXIT_STATUS_SYSTEMD },
      37             :         [EXIT_LIMITS] =                  { "LIMITS",                  EXIT_STATUS_SYSTEMD },
      38             :         [EXIT_OOM_ADJUST] =              { "OOM_ADJUST",              EXIT_STATUS_SYSTEMD },
      39             :         [EXIT_SIGNAL_MASK] =             { "SIGNAL_MASK",             EXIT_STATUS_SYSTEMD },
      40             :         [EXIT_STDIN] =                   { "STDIN",                   EXIT_STATUS_SYSTEMD },
      41             :         [EXIT_STDOUT] =                  { "STDOUT",                  EXIT_STATUS_SYSTEMD },
      42             :         [EXIT_CHROOT] =                  { "CHROOT",                  EXIT_STATUS_SYSTEMD },
      43             :         [EXIT_IOPRIO] =                  { "IOPRIO",                  EXIT_STATUS_SYSTEMD },
      44             :         [EXIT_TIMERSLACK] =              { "TIMERSLACK",              EXIT_STATUS_SYSTEMD },
      45             :         [EXIT_SECUREBITS] =              { "SECUREBITS",              EXIT_STATUS_SYSTEMD },
      46             :         [EXIT_SETSCHEDULER] =            { "SETSCHEDULER",            EXIT_STATUS_SYSTEMD },
      47             :         [EXIT_CPUAFFINITY] =             { "CPUAFFINITY",             EXIT_STATUS_SYSTEMD },
      48             :         [EXIT_GROUP] =                   { "GROUP",                   EXIT_STATUS_SYSTEMD },
      49             :         [EXIT_USER] =                    { "USER",                    EXIT_STATUS_SYSTEMD },
      50             :         [EXIT_CAPABILITIES] =            { "CAPABILITIES",            EXIT_STATUS_SYSTEMD },
      51             :         [EXIT_CGROUP] =                  { "CGROUP",                  EXIT_STATUS_SYSTEMD },
      52             :         [EXIT_SETSID] =                  { "SETSID",                  EXIT_STATUS_SYSTEMD },
      53             :         [EXIT_CONFIRM] =                 { "CONFIRM",                 EXIT_STATUS_SYSTEMD },
      54             :         [EXIT_STDERR] =                  { "STDERR",                  EXIT_STATUS_SYSTEMD },
      55             :         [EXIT_PAM] =                     { "PAM",                     EXIT_STATUS_SYSTEMD },
      56             :         [EXIT_NETWORK] =                 { "NETWORK",                 EXIT_STATUS_SYSTEMD },
      57             :         [EXIT_NAMESPACE] =               { "NAMESPACE",               EXIT_STATUS_SYSTEMD },
      58             :         [EXIT_NO_NEW_PRIVILEGES] =       { "NO_NEW_PRIVILEGES",       EXIT_STATUS_SYSTEMD },
      59             :         [EXIT_SECCOMP] =                 { "SECCOMP",                 EXIT_STATUS_SYSTEMD },
      60             :         [EXIT_SELINUX_CONTEXT] =         { "SELINUX_CONTEXT",         EXIT_STATUS_SYSTEMD },
      61             :         [EXIT_PERSONALITY] =             { "PERSONALITY",             EXIT_STATUS_SYSTEMD },
      62             :         [EXIT_APPARMOR_PROFILE] =        { "APPARMOR",                EXIT_STATUS_SYSTEMD },
      63             :         [EXIT_ADDRESS_FAMILIES] =        { "ADDRESS_FAMILIES",        EXIT_STATUS_SYSTEMD },
      64             :         [EXIT_RUNTIME_DIRECTORY] =       { "RUNTIME_DIRECTORY",       EXIT_STATUS_SYSTEMD },
      65             :         [EXIT_CHOWN] =                   { "CHOWN",                   EXIT_STATUS_SYSTEMD },
      66             :         [EXIT_SMACK_PROCESS_LABEL] =     { "SMACK_PROCESS_LABEL",     EXIT_STATUS_SYSTEMD },
      67             :         [EXIT_KEYRING] =                 { "KEYRING",                 EXIT_STATUS_SYSTEMD },
      68             :         [EXIT_STATE_DIRECTORY] =         { "STATE_DIRECTORY",         EXIT_STATUS_SYSTEMD },
      69             :         [EXIT_CACHE_DIRECTORY] =         { "CACHE_DIRECTORY",         EXIT_STATUS_SYSTEMD },
      70             :         [EXIT_LOGS_DIRECTORY] =          { "LOGS_DIRECTORY",          EXIT_STATUS_SYSTEMD },
      71             :         [EXIT_CONFIGURATION_DIRECTORY] = { "CONFIGURATION_DIRECTORY", EXIT_STATUS_SYSTEMD },
      72             :         [EXIT_NUMA_POLICY] =             { "NUMA_POLICY",             EXIT_STATUS_SYSTEMD },
      73             :         [EXIT_EXCEPTION] =               { "EXCEPTION",               EXIT_STATUS_SYSTEMD },
      74             : 
      75             :         [EXIT_INVALIDARGUMENT] =         { "INVALIDARGUMENT",         EXIT_STATUS_LSB },
      76             :         [EXIT_NOTIMPLEMENTED] =          { "NOTIMPLEMENTED",          EXIT_STATUS_LSB },
      77             :         [EXIT_NOPERMISSION] =            { "NOPERMISSION",            EXIT_STATUS_LSB },
      78             :         [EXIT_NOTINSTALLED] =            { "NOTINSTALLED",            EXIT_STATUS_LSB },
      79             :         [EXIT_NOTCONFIGURED] =           { "NOTCONFIGURED",           EXIT_STATUS_LSB },
      80             :         [EXIT_NOTRUNNING] =              { "NOTRUNNING",              EXIT_STATUS_LSB },
      81             : 
      82             :         [EX_USAGE] =                     { "USAGE",                   EXIT_STATUS_BSD },
      83             :         [EX_DATAERR] =                   { "DATAERR",                 EXIT_STATUS_BSD },
      84             :         [EX_NOINPUT] =                   { "NOINPUT",                 EXIT_STATUS_BSD },
      85             :         [EX_NOUSER] =                    { "NOUSER",                  EXIT_STATUS_BSD },
      86             :         [EX_NOHOST] =                    { "NOHOST",                  EXIT_STATUS_BSD },
      87             :         [EX_UNAVAILABLE] =               { "UNAVAILABLE",             EXIT_STATUS_BSD },
      88             :         [EX_SOFTWARE] =                  { "SOFTWARE",                EXIT_STATUS_BSD },
      89             :         [EX_OSERR] =                     { "OSERR",                   EXIT_STATUS_BSD },
      90             :         [EX_OSFILE] =                    { "OSFILE",                  EXIT_STATUS_BSD },
      91             :         [EX_CANTCREAT] =                 { "CANTCREAT",               EXIT_STATUS_BSD },
      92             :         [EX_IOERR] =                     { "IOERR",                   EXIT_STATUS_BSD },
      93             :         [EX_TEMPFAIL] =                  { "TEMPFAIL",                EXIT_STATUS_BSD },
      94             :         [EX_PROTOCOL] =                  { "PROTOCOL",                EXIT_STATUS_BSD },
      95             :         [EX_NOPERM] =                    { "NOPERM",                  EXIT_STATUS_BSD },
      96             :         [EX_CONFIG] =                    { "CONFIG",                  EXIT_STATUS_BSD },
      97             : };
      98             : 
      99         262 : const char* exit_status_to_string(int code, ExitStatusClass class) {
     100         262 :         if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
     101           2 :                 return NULL;
     102         260 :         return class & exit_status_mappings[code].class ? exit_status_mappings[code].name : NULL;
     103             : }
     104             : 
     105         258 : const char* exit_status_class(int code) {
     106         258 :         if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
     107           2 :                 return NULL;
     108             : 
     109         256 :         switch (exit_status_mappings[code].class) {
     110           2 :         case EXIT_STATUS_LIBC:
     111           2 :                 return "libc";
     112          42 :         case EXIT_STATUS_SYSTEMD:
     113          42 :                 return "systemd";
     114           6 :         case EXIT_STATUS_LSB:
     115           6 :                 return "LSB";
     116          15 :         case EXIT_STATUS_BSD:
     117          15 :                 return "BSD";
     118         191 :         default: return NULL;
     119             :         }
     120             : }
     121             : 
     122          71 : int exit_status_from_string(const char *s) {
     123             :         uint8_t val;
     124             :         int r;
     125             : 
     126       11490 :         for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++)
     127       11486 :                 if (streq_ptr(s, exit_status_mappings[i].name))
     128          67 :                         return i;
     129             : 
     130           4 :         r = safe_atou8(s, &val);
     131           4 :         if (r < 0)
     132           3 :                 return r;
     133             : 
     134           1 :         return val;
     135             : }
     136             : 
     137           0 : bool is_clean_exit(int code, int status, ExitClean clean, const ExitStatusSet *success_status) {
     138           0 :         if (code == CLD_EXITED)
     139           0 :                 return status == 0 ||
     140           0 :                        (success_status &&
     141           0 :                         bitmap_isset(&success_status->status, status));
     142             : 
     143             :         /* If a daemon does not implement handlers for some of the signals, we do not consider this an
     144             :            unclean shutdown */
     145           0 :         if (code == CLD_KILLED)
     146             :                 return
     147           0 :                         (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
     148           0 :                         (success_status &&
     149           0 :                          bitmap_isset(&success_status->signal, status));
     150             : 
     151           0 :         return false;
     152             : }
     153             : 
     154         138 : void exit_status_set_free(ExitStatusSet *x) {
     155         138 :         assert(x);
     156             : 
     157         138 :         bitmap_clear(&x->status);
     158         138 :         bitmap_clear(&x->signal);
     159         138 : }
     160             : 
     161          17 : bool exit_status_set_is_empty(const ExitStatusSet *x) {
     162          17 :         if (!x)
     163           0 :                 return true;
     164             : 
     165          17 :         return bitmap_isclear(&x->status) && bitmap_isclear(&x->signal);
     166             : }
     167             : 
     168           0 : bool exit_status_set_test(const ExitStatusSet *x, int code, int status) {
     169           0 :         if (code == CLD_EXITED && bitmap_isset(&x->status, status))
     170           0 :                 return true;
     171             : 
     172           0 :         if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && bitmap_isset(&x->signal, status))
     173           0 :                 return true;
     174             : 
     175           0 :         return false;
     176             : }

Generated by: LCOV version 1.14