LCOV - code coverage report
Current view: top level - notify - notify.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 26 96 27.1 %
Date: 2019-08-22 15:41:25 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <getopt.h>
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : #include <unistd.h>
       8             : 
       9             : #include "sd-daemon.h"
      10             : 
      11             : #include "alloc-util.h"
      12             : #include "env-util.h"
      13             : #include "format-util.h"
      14             : #include "log.h"
      15             : #include "main-func.h"
      16             : #include "parse-util.h"
      17             : #include "pretty-print.h"
      18             : #include "string-util.h"
      19             : #include "strv.h"
      20             : #include "user-util.h"
      21             : #include "util.h"
      22             : 
      23             : static bool arg_ready = false;
      24             : static pid_t arg_pid = 0;
      25             : static const char *arg_status = NULL;
      26             : static bool arg_booted = false;
      27             : static uid_t arg_uid = UID_INVALID;
      28             : static gid_t arg_gid = GID_INVALID;
      29             : 
      30           3 : static int help(void) {
      31           3 :         _cleanup_free_ char *link = NULL;
      32             :         int r;
      33             : 
      34           3 :         r = terminal_urlify_man("systemd-notify", "1", &link);
      35           3 :         if (r < 0)
      36           0 :                 return log_oom();
      37             : 
      38           3 :         printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
      39             :                "Notify the init system about service status updates.\n\n"
      40             :                "  -h --help            Show this help\n"
      41             :                "     --version         Show package version\n"
      42             :                "     --ready           Inform the init system about service start-up completion\n"
      43             :                "     --pid[=PID]       Set main PID of daemon\n"
      44             :                "     --uid=USER        Set user to send from\n"
      45             :                "     --status=TEXT     Set status text\n"
      46             :                "     --booted          Check if the system was booted up with systemd\n"
      47             :                "\nSee the %s for details.\n"
      48             :                , program_invocation_short_name
      49             :                , link
      50             :         );
      51             : 
      52           3 :         return 0;
      53             : }
      54             : 
      55           4 : static int parse_argv(int argc, char *argv[]) {
      56             : 
      57             :         enum {
      58             :                 ARG_READY = 0x100,
      59             :                 ARG_VERSION,
      60             :                 ARG_PID,
      61             :                 ARG_STATUS,
      62             :                 ARG_BOOTED,
      63             :                 ARG_UID,
      64             :         };
      65             : 
      66             :         static const struct option options[] = {
      67             :                 { "help",      no_argument,       NULL, 'h'           },
      68             :                 { "version",   no_argument,       NULL, ARG_VERSION   },
      69             :                 { "ready",     no_argument,       NULL, ARG_READY     },
      70             :                 { "pid",       optional_argument, NULL, ARG_PID       },
      71             :                 { "status",    required_argument, NULL, ARG_STATUS    },
      72             :                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
      73             :                 { "uid",       required_argument, NULL, ARG_UID       },
      74             :                 {}
      75             :         };
      76             : 
      77             :         int c, r;
      78             : 
      79           4 :         assert(argc >= 0);
      80           4 :         assert(argv);
      81             : 
      82           4 :         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
      83             : 
      84           4 :                 switch (c) {
      85             : 
      86           3 :                 case 'h':
      87           3 :                         return help();
      88             : 
      89           0 :                 case ARG_VERSION:
      90           0 :                         return version();
      91             : 
      92           0 :                 case ARG_READY:
      93           0 :                         arg_ready = true;
      94           0 :                         break;
      95             : 
      96           0 :                 case ARG_PID:
      97             : 
      98           0 :                         if (optarg) {
      99           0 :                                 if (parse_pid(optarg, &arg_pid) < 0)
     100           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     101             :                                                                "Failed to parse PID %s.", optarg);
     102             :                         } else
     103           0 :                                 arg_pid = getppid();
     104             : 
     105           0 :                         break;
     106             : 
     107           0 :                 case ARG_STATUS:
     108           0 :                         arg_status = optarg;
     109           0 :                         break;
     110             : 
     111           0 :                 case ARG_BOOTED:
     112           0 :                         arg_booted = true;
     113           0 :                         break;
     114             : 
     115           0 :                 case ARG_UID: {
     116           0 :                         const char *u = optarg;
     117             : 
     118           0 :                         r = get_user_creds(&u, &arg_uid, &arg_gid, NULL, NULL, 0);
     119           0 :                         if (r == -ESRCH) /* If the user doesn't exist, then accept it anyway as numeric */
     120           0 :                                 r = parse_uid(u, &arg_uid);
     121           0 :                         if (r < 0)
     122           0 :                                 return log_error_errno(r, "Can't resolve user %s: %m", optarg);
     123             : 
     124           0 :                         break;
     125             :                 }
     126             : 
     127           1 :                 case '?':
     128           1 :                         return -EINVAL;
     129             : 
     130           0 :                 default:
     131           0 :                         assert_not_reached("Unhandled option");
     132             :                 }
     133             :         }
     134             : 
     135           0 :         if (optind >= argc &&
     136           0 :             !arg_ready &&
     137           0 :             !arg_status &&
     138           0 :             !arg_pid &&
     139           0 :             !arg_booted) {
     140           0 :                 help();
     141           0 :                 return -EINVAL;
     142             :         }
     143             : 
     144           0 :         return 1;
     145             : }
     146             : 
     147           4 : static int run(int argc, char* argv[]) {
     148           4 :         _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
     149           4 :         _cleanup_strv_free_ char **final_env = NULL;
     150             :         char* our_env[4];
     151           4 :         unsigned i = 0;
     152             :         int r;
     153             : 
     154           4 :         log_show_color(true);
     155           4 :         log_parse_environment();
     156           4 :         log_open();
     157             : 
     158           4 :         r = parse_argv(argc, argv);
     159           4 :         if (r <= 0)
     160           4 :                 return r;
     161             : 
     162           0 :         if (arg_booted)
     163           0 :                 return sd_booted() <= 0;
     164             : 
     165           0 :         if (arg_ready)
     166           0 :                 our_env[i++] = (char*) "READY=1";
     167             : 
     168           0 :         if (arg_status) {
     169           0 :                 status = strjoin("STATUS=", arg_status);
     170           0 :                 if (!status)
     171           0 :                         return log_oom();
     172             : 
     173           0 :                 our_env[i++] = status;
     174             :         }
     175             : 
     176           0 :         if (arg_pid > 0) {
     177           0 :                 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0)
     178           0 :                         return log_oom();
     179             : 
     180           0 :                 our_env[i++] = cpid;
     181             :         }
     182             : 
     183           0 :         our_env[i++] = NULL;
     184             : 
     185           0 :         final_env = strv_env_merge(2, our_env, argv + optind);
     186           0 :         if (!final_env)
     187           0 :                 return log_oom();
     188             : 
     189           0 :         if (strv_isempty(final_env))
     190           0 :                 return 0;
     191             : 
     192           0 :         n = strv_join(final_env, "\n");
     193           0 :         if (!n)
     194           0 :                 return log_oom();
     195             : 
     196             :         /* If this is requested change to the requested UID/GID. Note that we only change the real UID here, and leave
     197             :            the effective UID in effect (which is 0 for this to work). That's because we want the privileges to fake the
     198             :            ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */
     199             : 
     200           0 :         if (arg_gid != GID_INVALID &&
     201           0 :             setregid(arg_gid, (gid_t) -1) < 0)
     202           0 :                 return log_error_errno(errno, "Failed to change GID: %m");
     203             : 
     204           0 :         if (arg_uid != UID_INVALID &&
     205           0 :             setreuid(arg_uid, (uid_t) -1) < 0)
     206           0 :                 return log_error_errno(errno, "Failed to change UID: %m");
     207             : 
     208           0 :         r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
     209           0 :         if (r < 0)
     210           0 :                 return log_error_errno(r, "Failed to notify init system: %m");
     211           0 :         if (r == 0)
     212           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
     213             :                                        "No status data could be sent: $NOTIFY_SOCKET was not set");
     214           0 :         return 0;
     215             : }
     216             : 
     217           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14