LCOV - code coverage report
Current view: top level - import - importd.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 627 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 34 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 490 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <sys/prctl.h>
       4                 :            : #include <sys/wait.h>
       5                 :            : 
       6                 :            : #include "sd-bus.h"
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "bus-common-errors.h"
      10                 :            : #include "bus-util.h"
      11                 :            : #include "def.h"
      12                 :            : #include "fd-util.h"
      13                 :            : #include "float.h"
      14                 :            : #include "hostname-util.h"
      15                 :            : #include "import-util.h"
      16                 :            : #include "machine-pool.h"
      17                 :            : #include "main-func.h"
      18                 :            : #include "missing.h"
      19                 :            : #include "mkdir.h"
      20                 :            : #include "parse-util.h"
      21                 :            : #include "path-util.h"
      22                 :            : #include "process-util.h"
      23                 :            : #include "signal-util.h"
      24                 :            : #include "socket-util.h"
      25                 :            : #include "stat-util.h"
      26                 :            : #include "string-table.h"
      27                 :            : #include "strv.h"
      28                 :            : #include "syslog-util.h"
      29                 :            : #include "user-util.h"
      30                 :            : #include "util.h"
      31                 :            : #include "web-util.h"
      32                 :            : 
      33                 :            : typedef struct Transfer Transfer;
      34                 :            : typedef struct Manager Manager;
      35                 :            : 
      36                 :            : typedef enum TransferType {
      37                 :            :         TRANSFER_IMPORT_TAR,
      38                 :            :         TRANSFER_IMPORT_RAW,
      39                 :            :         TRANSFER_IMPORT_FS,
      40                 :            :         TRANSFER_EXPORT_TAR,
      41                 :            :         TRANSFER_EXPORT_RAW,
      42                 :            :         TRANSFER_PULL_TAR,
      43                 :            :         TRANSFER_PULL_RAW,
      44                 :            :         _TRANSFER_TYPE_MAX,
      45                 :            :         _TRANSFER_TYPE_INVALID = -1,
      46                 :            : } TransferType;
      47                 :            : 
      48                 :            : struct Transfer {
      49                 :            :         Manager *manager;
      50                 :            : 
      51                 :            :         uint32_t id;
      52                 :            :         char *object_path;
      53                 :            : 
      54                 :            :         TransferType type;
      55                 :            :         ImportVerify verify;
      56                 :            : 
      57                 :            :         char *remote;
      58                 :            :         char *local;
      59                 :            :         bool force_local;
      60                 :            :         bool read_only;
      61                 :            : 
      62                 :            :         char *format;
      63                 :            : 
      64                 :            :         pid_t pid;
      65                 :            : 
      66                 :            :         int log_fd;
      67                 :            : 
      68                 :            :         char log_message[LINE_MAX];
      69                 :            :         size_t log_message_size;
      70                 :            : 
      71                 :            :         sd_event_source *pid_event_source;
      72                 :            :         sd_event_source *log_event_source;
      73                 :            : 
      74                 :            :         unsigned n_canceled;
      75                 :            :         unsigned progress_percent;
      76                 :            : 
      77                 :            :         int stdin_fd;
      78                 :            :         int stdout_fd;
      79                 :            : };
      80                 :            : 
      81                 :            : struct Manager {
      82                 :            :         sd_event *event;
      83                 :            :         sd_bus *bus;
      84                 :            : 
      85                 :            :         uint32_t current_transfer_id;
      86                 :            :         Hashmap *transfers;
      87                 :            : 
      88                 :            :         Hashmap *polkit_registry;
      89                 :            : 
      90                 :            :         int notify_fd;
      91                 :            : 
      92                 :            :         sd_event_source *notify_event_source;
      93                 :            : };
      94                 :            : 
      95                 :            : #define TRANSFERS_MAX 64
      96                 :            : 
      97                 :            : static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
      98                 :            :         [TRANSFER_IMPORT_TAR] = "import-tar",
      99                 :            :         [TRANSFER_IMPORT_RAW] = "import-raw",
     100                 :            :         [TRANSFER_IMPORT_FS] = "import-fs",
     101                 :            :         [TRANSFER_EXPORT_TAR] = "export-tar",
     102                 :            :         [TRANSFER_EXPORT_RAW] = "export-raw",
     103                 :            :         [TRANSFER_PULL_TAR] = "pull-tar",
     104                 :            :         [TRANSFER_PULL_RAW] = "pull-raw",
     105                 :            : };
     106                 :            : 
     107   [ #  #  #  # ]:          0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
     108                 :            : 
     109                 :          0 : static Transfer *transfer_unref(Transfer *t) {
     110         [ #  # ]:          0 :         if (!t)
     111                 :          0 :                 return NULL;
     112                 :            : 
     113         [ #  # ]:          0 :         if (t->manager)
     114                 :          0 :                 hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id));
     115                 :            : 
     116                 :          0 :         sd_event_source_unref(t->pid_event_source);
     117                 :          0 :         sd_event_source_unref(t->log_event_source);
     118                 :            : 
     119                 :          0 :         free(t->remote);
     120                 :          0 :         free(t->local);
     121                 :          0 :         free(t->format);
     122                 :          0 :         free(t->object_path);
     123                 :            : 
     124         [ #  # ]:          0 :         if (t->pid > 0) {
     125                 :          0 :                 (void) kill_and_sigcont(t->pid, SIGKILL);
     126                 :          0 :                 (void) wait_for_terminate(t->pid, NULL);
     127                 :            :         }
     128                 :            : 
     129                 :          0 :         safe_close(t->log_fd);
     130                 :          0 :         safe_close(t->stdin_fd);
     131                 :          0 :         safe_close(t->stdout_fd);
     132                 :            : 
     133                 :          0 :         return mfree(t);
     134                 :            : }
     135                 :            : 
     136         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref);
     137                 :            : 
     138                 :          0 : static int transfer_new(Manager *m, Transfer **ret) {
     139                 :          0 :         _cleanup_(transfer_unrefp) Transfer *t = NULL;
     140                 :            :         uint32_t id;
     141                 :            :         int r;
     142                 :            : 
     143         [ #  # ]:          0 :         assert(m);
     144         [ #  # ]:          0 :         assert(ret);
     145                 :            : 
     146         [ #  # ]:          0 :         if (hashmap_size(m->transfers) >= TRANSFERS_MAX)
     147                 :          0 :                 return -E2BIG;
     148                 :            : 
     149                 :          0 :         r = hashmap_ensure_allocated(&m->transfers, &trivial_hash_ops);
     150         [ #  # ]:          0 :         if (r < 0)
     151                 :          0 :                 return r;
     152                 :            : 
     153                 :          0 :         t = new(Transfer, 1);
     154         [ #  # ]:          0 :         if (!t)
     155                 :          0 :                 return -ENOMEM;
     156                 :            : 
     157                 :          0 :         *t = (Transfer) {
     158                 :            :                 .type = _TRANSFER_TYPE_INVALID,
     159                 :            :                 .log_fd = -1,
     160                 :            :                 .stdin_fd = -1,
     161                 :            :                 .stdout_fd = -1,
     162                 :            :                 .verify = _IMPORT_VERIFY_INVALID,
     163                 :            :                 .progress_percent= (unsigned) -1,
     164                 :            :         };
     165                 :            : 
     166                 :          0 :         id = m->current_transfer_id + 1;
     167                 :            : 
     168         [ #  # ]:          0 :         if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0)
     169                 :          0 :                 return -ENOMEM;
     170                 :            : 
     171                 :          0 :         r = hashmap_put(m->transfers, UINT32_TO_PTR(id), t);
     172         [ #  # ]:          0 :         if (r < 0)
     173                 :          0 :                 return r;
     174                 :            : 
     175                 :          0 :         m->current_transfer_id = id;
     176                 :            : 
     177                 :          0 :         t->manager = m;
     178                 :          0 :         t->id = id;
     179                 :            : 
     180                 :          0 :         *ret = TAKE_PTR(t);
     181                 :            : 
     182                 :          0 :         return 0;
     183                 :            : }
     184                 :            : 
     185                 :          0 : static double transfer_percent_as_double(Transfer *t) {
     186         [ #  # ]:          0 :         assert(t);
     187                 :            : 
     188         [ #  # ]:          0 :         if (t->progress_percent == (unsigned) -1)
     189                 :          0 :                 return -DBL_MAX;
     190                 :            : 
     191                 :          0 :         return (double) t->progress_percent / 100.0;
     192                 :            : }
     193                 :            : 
     194                 :          0 : static void transfer_send_log_line(Transfer *t, const char *line) {
     195                 :          0 :         int r, priority = LOG_INFO;
     196                 :            : 
     197         [ #  # ]:          0 :         assert(t);
     198         [ #  # ]:          0 :         assert(line);
     199                 :            : 
     200                 :          0 :         syslog_parse_priority(&line, &priority, true);
     201                 :            : 
     202         [ #  # ]:          0 :         log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
     203                 :            : 
     204                 :          0 :         r = sd_bus_emit_signal(
     205                 :          0 :                         t->manager->bus,
     206                 :          0 :                         t->object_path,
     207                 :            :                         "org.freedesktop.import1.Transfer",
     208                 :            :                         "LogMessage",
     209                 :            :                         "us",
     210                 :            :                         priority,
     211                 :            :                         line);
     212         [ #  # ]:          0 :         if (r < 0)
     213         [ #  # ]:          0 :                 log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
     214                 :          0 :  }
     215                 :            : 
     216                 :          0 : static void transfer_send_logs(Transfer *t, bool flush) {
     217         [ #  # ]:          0 :         assert(t);
     218                 :            : 
     219                 :            :         /* Try to send out all log messages, if we can. But if we
     220                 :            :          * can't we remove the messages from the buffer, but don't
     221                 :            :          * fail */
     222                 :            : 
     223         [ #  # ]:          0 :         while (t->log_message_size > 0) {
     224      [ #  #  # ]:          0 :                 _cleanup_free_ char *n = NULL;
     225                 :            :                 char *e;
     226                 :            : 
     227         [ #  # ]:          0 :                 if (t->log_message_size >= sizeof(t->log_message))
     228                 :          0 :                         e = t->log_message + sizeof(t->log_message);
     229                 :            :                 else {
     230                 :            :                         char *a, *b;
     231                 :            : 
     232                 :          0 :                         a = memchr(t->log_message, 0, t->log_message_size);
     233                 :          0 :                         b = memchr(t->log_message, '\n', t->log_message_size);
     234                 :            : 
     235   [ #  #  #  # ]:          0 :                         if (a && b)
     236                 :          0 :                                 e = a < b ? a : b;
     237         [ #  # ]:          0 :                         else if (a)
     238                 :          0 :                                 e = a;
     239                 :            :                         else
     240                 :          0 :                                 e = b;
     241                 :            :                 }
     242                 :            : 
     243         [ #  # ]:          0 :                 if (!e) {
     244         [ #  # ]:          0 :                         if (!flush)
     245                 :          0 :                                 return;
     246                 :            : 
     247                 :          0 :                         e = t->log_message + t->log_message_size;
     248                 :            :                 }
     249                 :            : 
     250                 :          0 :                 n = strndup(t->log_message, e - t->log_message);
     251                 :            : 
     252                 :            :                 /* Skip over NUL and newlines */
     253   [ #  #  #  #  :          0 :                 while (e < t->log_message + t->log_message_size && IN_SET(*e, 0, '\n'))
                   #  # ]
     254                 :          0 :                         e++;
     255                 :            : 
     256                 :          0 :                 memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
     257                 :          0 :                 t->log_message_size -= e - t->log_message;
     258                 :            : 
     259         [ #  # ]:          0 :                 if (!n) {
     260                 :          0 :                         log_oom();
     261                 :          0 :                         continue;
     262                 :            :                 }
     263                 :            : 
     264         [ #  # ]:          0 :                 if (isempty(n))
     265                 :          0 :                         continue;
     266                 :            : 
     267                 :          0 :                 transfer_send_log_line(t, n);
     268                 :            :         }
     269                 :            : }
     270                 :            : 
     271                 :          0 : static int transfer_finalize(Transfer *t, bool success) {
     272                 :            :         int r;
     273                 :            : 
     274         [ #  # ]:          0 :         assert(t);
     275                 :            : 
     276                 :          0 :         transfer_send_logs(t, true);
     277                 :            : 
     278         [ #  # ]:          0 :         r = sd_bus_emit_signal(
     279                 :          0 :                         t->manager->bus,
     280                 :            :                         "/org/freedesktop/import1",
     281                 :            :                         "org.freedesktop.import1.Manager",
     282                 :            :                         "TransferRemoved",
     283                 :            :                         "uos",
     284                 :            :                         t->id,
     285                 :            :                         t->object_path,
     286                 :            :                         success ? "done" :
     287         [ #  # ]:          0 :                         t->n_canceled > 0 ? "canceled" : "failed");
     288                 :            : 
     289         [ #  # ]:          0 :         if (r < 0)
     290         [ #  # ]:          0 :                 log_error_errno(r, "Cannot emit message: %m");
     291                 :            : 
     292                 :          0 :         transfer_unref(t);
     293                 :          0 :         return 0;
     294                 :            : }
     295                 :            : 
     296                 :          0 : static int transfer_cancel(Transfer *t) {
     297                 :            :         int r;
     298                 :            : 
     299         [ #  # ]:          0 :         assert(t);
     300                 :            : 
     301         [ #  # ]:          0 :         r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
     302         [ #  # ]:          0 :         if (r < 0)
     303                 :          0 :                 return r;
     304                 :            : 
     305                 :          0 :         t->n_canceled++;
     306                 :          0 :         return 0;
     307                 :            : }
     308                 :            : 
     309                 :          0 : static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
     310                 :          0 :         Transfer *t = userdata;
     311                 :          0 :         bool success = false;
     312                 :            : 
     313         [ #  # ]:          0 :         assert(s);
     314         [ #  # ]:          0 :         assert(t);
     315                 :            : 
     316         [ #  # ]:          0 :         if (si->si_code == CLD_EXITED) {
     317         [ #  # ]:          0 :                 if (si->si_status != 0)
     318         [ #  # ]:          0 :                         log_error("Transfer process failed with exit code %i.", si->si_status);
     319                 :            :                 else {
     320         [ #  # ]:          0 :                         log_debug("Transfer process succeeded.");
     321                 :          0 :                         success = true;
     322                 :            :                 }
     323                 :            : 
     324   [ #  #  #  # ]:          0 :         } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED))
     325         [ #  # ]:          0 :                 log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status));
     326                 :            :         else
     327         [ #  # ]:          0 :                 log_error("Transfer process failed due to unknown reason.");
     328                 :            : 
     329                 :          0 :         t->pid = 0;
     330                 :            : 
     331                 :          0 :         return transfer_finalize(t, success);
     332                 :            : }
     333                 :            : 
     334                 :          0 : static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     335                 :          0 :         Transfer *t = userdata;
     336                 :            :         ssize_t l;
     337                 :            : 
     338         [ #  # ]:          0 :         assert(s);
     339         [ #  # ]:          0 :         assert(t);
     340                 :            : 
     341                 :          0 :         l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
     342         [ #  # ]:          0 :         if (l < 0)
     343         [ #  # ]:          0 :                 log_error_errno(errno, "Failed to read log message: %m");
     344         [ #  # ]:          0 :         if (l <= 0) {
     345                 :            :                 /* EOF/read error. We just close the pipe here, and
     346                 :            :                  * close the watch, waiting for the SIGCHLD to arrive,
     347                 :            :                  * before we do anything else. */
     348                 :          0 :                 t->log_event_source = sd_event_source_unref(t->log_event_source);
     349                 :          0 :                 return 0;
     350                 :            :         }
     351                 :            : 
     352                 :          0 :         t->log_message_size += l;
     353                 :            : 
     354                 :          0 :         transfer_send_logs(t, false);
     355                 :            : 
     356                 :          0 :         return 0;
     357                 :            : }
     358                 :            : 
     359                 :          0 : static int transfer_start(Transfer *t) {
     360                 :          0 :         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
     361                 :            :         int r;
     362                 :            : 
     363         [ #  # ]:          0 :         assert(t);
     364         [ #  # ]:          0 :         assert(t->pid <= 0);
     365                 :            : 
     366         [ #  # ]:          0 :         if (pipe2(pipefd, O_CLOEXEC) < 0)
     367                 :          0 :                 return -errno;
     368                 :            : 
     369                 :          0 :         r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
     370         [ #  # ]:          0 :         if (r < 0)
     371                 :          0 :                 return r;
     372         [ #  # ]:          0 :         if (r == 0) {
     373                 :          0 :                 const char *cmd[] = {
     374                 :            :                         NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
     375                 :            :                         NULL, /* tar, raw  */
     376                 :            :                         NULL, /* --verify= */
     377                 :            :                         NULL, /* verify argument */
     378                 :            :                         NULL, /* maybe --force */
     379                 :            :                         NULL, /* maybe --read-only */
     380                 :            :                         NULL, /* if so: the actual URL */
     381                 :            :                         NULL, /* maybe --format= */
     382                 :            :                         NULL, /* if so: the actual format */
     383                 :            :                         NULL, /* remote */
     384                 :            :                         NULL, /* local */
     385                 :            :                         NULL
     386                 :            :                 };
     387                 :          0 :                 unsigned k = 0;
     388                 :            : 
     389                 :            :                 /* Child */
     390                 :            : 
     391                 :          0 :                 pipefd[0] = safe_close(pipefd[0]);
     392                 :            : 
     393                 :          0 :                 r = rearrange_stdio(t->stdin_fd,
     394         [ #  # ]:          0 :                                     t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd,
     395                 :            :                                     pipefd[1]);
     396         [ #  # ]:          0 :                 if (r < 0) {
     397         [ #  # ]:          0 :                         log_error_errno(r, "Failed to set stdin/stdout/stderr: %m");
     398                 :          0 :                         _exit(EXIT_FAILURE);
     399                 :            :                 }
     400                 :            : 
     401   [ #  #  #  # ]:          0 :                 if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
     402                 :          0 :                     setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
     403         [ #  # ]:          0 :                         log_error_errno(errno, "setenv() failed: %m");
     404                 :          0 :                         _exit(EXIT_FAILURE);
     405                 :            :                 }
     406                 :            : 
     407   [ #  #  #  #  :          0 :                 switch (t->type) {
                      # ]
     408                 :            : 
     409                 :          0 :                 case TRANSFER_IMPORT_TAR:
     410                 :            :                 case TRANSFER_IMPORT_RAW:
     411                 :          0 :                         cmd[k++] = SYSTEMD_IMPORT_PATH;
     412                 :          0 :                         break;
     413                 :            : 
     414                 :          0 :                 case TRANSFER_IMPORT_FS:
     415                 :          0 :                         cmd[k++] = SYSTEMD_IMPORT_FS_PATH;
     416                 :          0 :                         break;
     417                 :            : 
     418                 :          0 :                 case TRANSFER_EXPORT_TAR:
     419                 :            :                 case TRANSFER_EXPORT_RAW:
     420                 :          0 :                         cmd[k++] = SYSTEMD_EXPORT_PATH;
     421                 :          0 :                         break;
     422                 :            : 
     423                 :          0 :                 case TRANSFER_PULL_TAR:
     424                 :            :                 case TRANSFER_PULL_RAW:
     425                 :          0 :                         cmd[k++] = SYSTEMD_PULL_PATH;
     426                 :          0 :                         break;
     427                 :            : 
     428                 :          0 :                 default:
     429                 :          0 :                         assert_not_reached("Unexpected transfer type");
     430                 :            :                 }
     431                 :            : 
     432   [ #  #  #  # ]:          0 :                 switch (t->type) {
     433                 :            : 
     434                 :          0 :                 case TRANSFER_IMPORT_TAR:
     435                 :            :                 case TRANSFER_EXPORT_TAR:
     436                 :            :                 case TRANSFER_PULL_TAR:
     437                 :          0 :                         cmd[k++] = "tar";
     438                 :          0 :                         break;
     439                 :            : 
     440                 :          0 :                 case TRANSFER_IMPORT_RAW:
     441                 :            :                 case TRANSFER_EXPORT_RAW:
     442                 :            :                 case TRANSFER_PULL_RAW:
     443                 :          0 :                         cmd[k++] = "raw";
     444                 :          0 :                         break;
     445                 :            : 
     446                 :          0 :                 case TRANSFER_IMPORT_FS:
     447                 :          0 :                         cmd[k++] = "run";
     448                 :          0 :                         break;
     449                 :            : 
     450                 :          0 :                 default:
     451                 :          0 :                         break;
     452                 :            :                 }
     453                 :            : 
     454         [ #  # ]:          0 :                 if (t->verify != _IMPORT_VERIFY_INVALID) {
     455                 :          0 :                         cmd[k++] = "--verify";
     456                 :          0 :                         cmd[k++] = import_verify_to_string(t->verify);
     457                 :            :                 }
     458                 :            : 
     459         [ #  # ]:          0 :                 if (t->force_local)
     460                 :          0 :                         cmd[k++] = "--force";
     461         [ #  # ]:          0 :                 if (t->read_only)
     462                 :          0 :                         cmd[k++] = "--read-only";
     463                 :            : 
     464         [ #  # ]:          0 :                 if (t->format) {
     465                 :          0 :                         cmd[k++] = "--format";
     466                 :          0 :                         cmd[k++] = t->format;
     467                 :            :                 }
     468                 :            : 
     469   [ #  #  #  # ]:          0 :                 if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) {
     470         [ #  # ]:          0 :                         if (t->remote)
     471                 :          0 :                                 cmd[k++] = t->remote;
     472                 :            :                         else
     473                 :          0 :                                 cmd[k++] = "-";
     474                 :            :                 }
     475                 :            : 
     476         [ #  # ]:          0 :                 if (t->local)
     477                 :          0 :                         cmd[k++] = t->local;
     478                 :          0 :                 cmd[k] = NULL;
     479                 :            : 
     480                 :          0 :                 execv(cmd[0], (char * const *) cmd);
     481         [ #  # ]:          0 :                 log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
     482                 :          0 :                 _exit(EXIT_FAILURE);
     483                 :            :         }
     484                 :            : 
     485                 :          0 :         pipefd[1] = safe_close(pipefd[1]);
     486                 :          0 :         t->log_fd = TAKE_FD(pipefd[0]);
     487                 :            : 
     488                 :          0 :         t->stdin_fd = safe_close(t->stdin_fd);
     489                 :            : 
     490                 :          0 :         r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
     491         [ #  # ]:          0 :         if (r < 0)
     492                 :          0 :                 return r;
     493                 :            : 
     494                 :          0 :         r = sd_event_add_io(t->manager->event, &t->log_event_source, t->log_fd, EPOLLIN, transfer_on_log, t);
     495         [ #  # ]:          0 :         if (r < 0)
     496                 :          0 :                 return r;
     497                 :            : 
     498                 :            :         /* Make sure always process logging before SIGCHLD */
     499                 :          0 :         r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
     500         [ #  # ]:          0 :         if (r < 0)
     501                 :          0 :                 return r;
     502                 :            : 
     503                 :          0 :         r = sd_bus_emit_signal(
     504                 :          0 :                         t->manager->bus,
     505                 :            :                         "/org/freedesktop/import1",
     506                 :            :                         "org.freedesktop.import1.Manager",
     507                 :            :                         "TransferNew",
     508                 :            :                         "uo",
     509                 :            :                         t->id,
     510                 :            :                         t->object_path);
     511         [ #  # ]:          0 :         if (r < 0)
     512                 :          0 :                 return r;
     513                 :            : 
     514                 :          0 :         return 0;
     515                 :            : }
     516                 :            : 
     517                 :          0 : static Manager *manager_unref(Manager *m) {
     518                 :            :         Transfer *t;
     519                 :            : 
     520         [ #  # ]:          0 :         if (!m)
     521                 :          0 :                 return NULL;
     522                 :            : 
     523                 :          0 :         sd_event_source_unref(m->notify_event_source);
     524                 :          0 :         safe_close(m->notify_fd);
     525                 :            : 
     526         [ #  # ]:          0 :         while ((t = hashmap_first(m->transfers)))
     527                 :          0 :                 transfer_unref(t);
     528                 :            : 
     529                 :          0 :         hashmap_free(m->transfers);
     530                 :            : 
     531                 :          0 :         bus_verify_polkit_async_registry_free(m->polkit_registry);
     532                 :            : 
     533                 :          0 :         m->bus = sd_bus_flush_close_unref(m->bus);
     534                 :          0 :         sd_event_unref(m->event);
     535                 :            : 
     536                 :          0 :         return mfree(m);
     537                 :            : }
     538                 :            : 
     539         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
     540                 :            : 
     541                 :          0 : static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     542                 :            : 
     543                 :            :         char buf[NOTIFY_BUFFER_MAX+1];
     544                 :          0 :         struct iovec iovec = {
     545                 :            :                 .iov_base = buf,
     546                 :            :                 .iov_len = sizeof(buf)-1,
     547                 :            :         };
     548                 :            :         union {
     549                 :            :                 struct cmsghdr cmsghdr;
     550                 :            :                 uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
     551                 :            :                             CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
     552                 :          0 :         } control = {};
     553                 :          0 :         struct msghdr msghdr = {
     554                 :            :                 .msg_iov = &iovec,
     555                 :            :                 .msg_iovlen = 1,
     556                 :            :                 .msg_control = &control,
     557                 :            :                 .msg_controllen = sizeof(control),
     558                 :            :         };
     559                 :          0 :         struct ucred *ucred = NULL;
     560                 :          0 :         Manager *m = userdata;
     561                 :            :         struct cmsghdr *cmsg;
     562                 :            :         char *p, *e;
     563                 :            :         Transfer *t;
     564                 :            :         Iterator i;
     565                 :            :         ssize_t n;
     566                 :            :         int r;
     567                 :            : 
     568                 :          0 :         n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
     569         [ #  # ]:          0 :         if (n < 0) {
     570   [ #  #  #  # ]:          0 :                 if (IN_SET(errno, EAGAIN, EINTR))
     571                 :          0 :                         return 0;
     572                 :            : 
     573                 :          0 :                 return -errno;
     574                 :            :         }
     575                 :            : 
     576                 :          0 :         cmsg_close_all(&msghdr);
     577                 :            : 
     578   [ #  #  #  # ]:          0 :         CMSG_FOREACH(cmsg, &msghdr)
     579         [ #  # ]:          0 :                 if (cmsg->cmsg_level == SOL_SOCKET &&
     580         [ #  # ]:          0 :                     cmsg->cmsg_type == SCM_CREDENTIALS &&
     581         [ #  # ]:          0 :                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
     582                 :          0 :                         ucred = (struct ucred*) CMSG_DATA(cmsg);
     583                 :            : 
     584         [ #  # ]:          0 :         if (msghdr.msg_flags & MSG_TRUNC) {
     585         [ #  # ]:          0 :                 log_warning("Got overly long notification datagram, ignoring.");
     586                 :          0 :                 return 0;
     587                 :            :         }
     588                 :            : 
     589   [ #  #  #  # ]:          0 :         if (!ucred || ucred->pid <= 0) {
     590         [ #  # ]:          0 :                 log_warning("Got notification datagram lacking credential information, ignoring.");
     591                 :          0 :                 return 0;
     592                 :            :         }
     593                 :            : 
     594         [ #  # ]:          0 :         HASHMAP_FOREACH(t, m->transfers, i)
     595         [ #  # ]:          0 :                 if (ucred->pid == t->pid)
     596                 :          0 :                         break;
     597                 :            : 
     598         [ #  # ]:          0 :         if (!t) {
     599         [ #  # ]:          0 :                 log_warning("Got notification datagram from unexpected peer, ignoring.");
     600                 :          0 :                 return 0;
     601                 :            :         }
     602                 :            : 
     603                 :          0 :         buf[n] = 0;
     604                 :            : 
     605                 :          0 :         p = startswith(buf, "X_IMPORT_PROGRESS=");
     606         [ #  # ]:          0 :         if (!p) {
     607                 :          0 :                 p = strstr(buf, "\nX_IMPORT_PROGRESS=");
     608         [ #  # ]:          0 :                 if (!p)
     609                 :          0 :                         return 0;
     610                 :            : 
     611                 :          0 :                 p += 19;
     612                 :            :         }
     613                 :            : 
     614                 :          0 :         e = strchrnul(p, '\n');
     615                 :          0 :         *e = 0;
     616                 :            : 
     617                 :          0 :         r = parse_percent(p);
     618         [ #  # ]:          0 :         if (r < 0) {
     619         [ #  # ]:          0 :                 log_warning("Got invalid percent value, ignoring.");
     620                 :          0 :                 return 0;
     621                 :            :         }
     622                 :            : 
     623                 :          0 :         t->progress_percent = (unsigned) r;
     624                 :            : 
     625         [ #  # ]:          0 :         log_debug("Got percentage from client: %u%%", t->progress_percent);
     626                 :          0 :         return 0;
     627                 :            : }
     628                 :            : 
     629                 :          0 : static int manager_new(Manager **ret) {
     630                 :          0 :         _cleanup_(manager_unrefp) Manager *m = NULL;
     631                 :            :         static const union sockaddr_union sa = {
     632                 :            :                 .un.sun_family = AF_UNIX,
     633                 :            :                 .un.sun_path = "/run/systemd/import/notify",
     634                 :            :         };
     635                 :            :         int r;
     636                 :            : 
     637         [ #  # ]:          0 :         assert(ret);
     638                 :            : 
     639                 :          0 :         m = new0(Manager, 1);
     640         [ #  # ]:          0 :         if (!m)
     641                 :          0 :                 return -ENOMEM;
     642                 :            : 
     643                 :          0 :         r = sd_event_default(&m->event);
     644         [ #  # ]:          0 :         if (r < 0)
     645                 :          0 :                 return r;
     646                 :            : 
     647                 :          0 :         sd_event_set_watchdog(m->event, true);
     648                 :            : 
     649                 :          0 :         r = sd_bus_default_system(&m->bus);
     650         [ #  # ]:          0 :         if (r < 0)
     651                 :          0 :                 return r;
     652                 :            : 
     653                 :          0 :         m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
     654         [ #  # ]:          0 :         if (m->notify_fd < 0)
     655                 :          0 :                 return -errno;
     656                 :            : 
     657                 :          0 :         (void) mkdir_parents_label(sa.un.sun_path, 0755);
     658                 :          0 :         (void) sockaddr_un_unlink(&sa.un);
     659                 :            : 
     660   [ #  #  #  #  :          0 :         if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
                   #  # ]
     661                 :          0 :                 return -errno;
     662                 :            : 
     663                 :          0 :         r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true);
     664         [ #  # ]:          0 :         if (r < 0)
     665                 :          0 :                 return r;
     666                 :            : 
     667                 :          0 :         r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m);
     668         [ #  # ]:          0 :         if (r < 0)
     669                 :          0 :                 return r;
     670                 :            : 
     671                 :          0 :         *ret = TAKE_PTR(m);
     672                 :            : 
     673                 :          0 :         return 0;
     674                 :            : }
     675                 :            : 
     676                 :          0 : static Transfer *manager_find(Manager *m, TransferType type, const char *remote) {
     677                 :            :         Transfer *t;
     678                 :            :         Iterator i;
     679                 :            : 
     680         [ #  # ]:          0 :         assert(m);
     681         [ #  # ]:          0 :         assert(type >= 0);
     682         [ #  # ]:          0 :         assert(type < _TRANSFER_TYPE_MAX);
     683                 :            : 
     684         [ #  # ]:          0 :         HASHMAP_FOREACH(t, m->transfers, i)
     685   [ #  #  #  # ]:          0 :                 if (t->type == type && streq_ptr(t->remote, remote))
     686                 :          0 :                         return t;
     687                 :            : 
     688                 :          0 :         return NULL;
     689                 :            : }
     690                 :            : 
     691                 :          0 : static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
     692                 :          0 :         _cleanup_(transfer_unrefp) Transfer *t = NULL;
     693                 :            :         int fd, force, read_only, r;
     694                 :            :         const char *local, *object;
     695                 :          0 :         Manager *m = userdata;
     696                 :            :         TransferType type;
     697                 :            :         uint32_t id;
     698                 :            : 
     699         [ #  # ]:          0 :         assert(msg);
     700         [ #  # ]:          0 :         assert(m);
     701                 :            : 
     702                 :          0 :         r = bus_verify_polkit_async(
     703                 :            :                         msg,
     704                 :            :                         CAP_SYS_ADMIN,
     705                 :            :                         "org.freedesktop.import1.import",
     706                 :            :                         NULL,
     707                 :            :                         false,
     708                 :            :                         UID_INVALID,
     709                 :            :                         &m->polkit_registry,
     710                 :            :                         error);
     711         [ #  # ]:          0 :         if (r < 0)
     712                 :          0 :                 return r;
     713         [ #  # ]:          0 :         if (r == 0)
     714                 :          0 :                 return 1; /* Will call us back */
     715                 :            : 
     716                 :          0 :         r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
     717         [ #  # ]:          0 :         if (r < 0)
     718                 :          0 :                 return r;
     719                 :            : 
     720                 :          0 :         r = fd_verify_regular(fd);
     721         [ #  # ]:          0 :         if (r < 0)
     722                 :          0 :                 return r;
     723                 :            : 
     724         [ #  # ]:          0 :         if (!machine_name_is_valid(local))
     725                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
     726                 :            : 
     727                 :          0 :         r = setup_machine_directory(error);
     728         [ #  # ]:          0 :         if (r < 0)
     729                 :          0 :                 return r;
     730                 :            : 
     731                 :          0 :         type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
     732                 :            : 
     733                 :          0 :         r = transfer_new(m, &t);
     734         [ #  # ]:          0 :         if (r < 0)
     735                 :          0 :                 return r;
     736                 :            : 
     737                 :          0 :         t->type = type;
     738                 :          0 :         t->force_local = force;
     739                 :          0 :         t->read_only = read_only;
     740                 :            : 
     741                 :          0 :         t->local = strdup(local);
     742         [ #  # ]:          0 :         if (!t->local)
     743                 :          0 :                 return -ENOMEM;
     744                 :            : 
     745                 :          0 :         t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     746         [ #  # ]:          0 :         if (t->stdin_fd < 0)
     747                 :          0 :                 return -errno;
     748                 :            : 
     749                 :          0 :         r = transfer_start(t);
     750         [ #  # ]:          0 :         if (r < 0)
     751                 :          0 :                 return r;
     752                 :            : 
     753                 :          0 :         object = t->object_path;
     754                 :          0 :         id = t->id;
     755                 :          0 :         t = NULL;
     756                 :            : 
     757                 :          0 :         return sd_bus_reply_method_return(msg, "uo", id, object);
     758                 :            : }
     759                 :            : 
     760                 :          0 : static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
     761                 :          0 :         _cleanup_(transfer_unrefp) Transfer *t = NULL;
     762                 :            :         int fd, force, read_only, r;
     763                 :            :         const char *local, *object;
     764                 :          0 :         Manager *m = userdata;
     765                 :            :         uint32_t id;
     766                 :            : 
     767         [ #  # ]:          0 :         assert(msg);
     768         [ #  # ]:          0 :         assert(m);
     769                 :            : 
     770                 :          0 :         r = bus_verify_polkit_async(
     771                 :            :                         msg,
     772                 :            :                         CAP_SYS_ADMIN,
     773                 :            :                         "org.freedesktop.import1.import",
     774                 :            :                         NULL,
     775                 :            :                         false,
     776                 :            :                         UID_INVALID,
     777                 :            :                         &m->polkit_registry,
     778                 :            :                         error);
     779         [ #  # ]:          0 :         if (r < 0)
     780                 :          0 :                 return r;
     781         [ #  # ]:          0 :         if (r == 0)
     782                 :          0 :                 return 1; /* Will call us back */
     783                 :            : 
     784                 :          0 :         r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
     785         [ #  # ]:          0 :         if (r < 0)
     786                 :          0 :                 return r;
     787                 :            : 
     788                 :          0 :         r = fd_verify_directory(fd);
     789         [ #  # ]:          0 :         if (r < 0)
     790                 :          0 :                 return r;
     791                 :            : 
     792         [ #  # ]:          0 :         if (!machine_name_is_valid(local))
     793                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
     794                 :            : 
     795                 :          0 :         r = setup_machine_directory(error);
     796         [ #  # ]:          0 :         if (r < 0)
     797                 :          0 :                 return r;
     798                 :            : 
     799                 :          0 :         r = transfer_new(m, &t);
     800         [ #  # ]:          0 :         if (r < 0)
     801                 :          0 :                 return r;
     802                 :            : 
     803                 :          0 :         t->type = TRANSFER_IMPORT_FS;
     804                 :          0 :         t->force_local = force;
     805                 :          0 :         t->read_only = read_only;
     806                 :            : 
     807                 :          0 :         t->local = strdup(local);
     808         [ #  # ]:          0 :         if (!t->local)
     809                 :          0 :                 return -ENOMEM;
     810                 :            : 
     811                 :          0 :         t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     812         [ #  # ]:          0 :         if (t->stdin_fd < 0)
     813                 :          0 :                 return -errno;
     814                 :            : 
     815                 :          0 :         r = transfer_start(t);
     816         [ #  # ]:          0 :         if (r < 0)
     817                 :          0 :                 return r;
     818                 :            : 
     819                 :          0 :         object = t->object_path;
     820                 :          0 :         id = t->id;
     821                 :          0 :         t = NULL;
     822                 :            : 
     823                 :          0 :         return sd_bus_reply_method_return(msg, "uo", id, object);
     824                 :            : }
     825                 :            : 
     826                 :          0 : static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
     827                 :          0 :         _cleanup_(transfer_unrefp) Transfer *t = NULL;
     828                 :            :         int fd, r;
     829                 :            :         const char *local, *object, *format;
     830                 :          0 :         Manager *m = userdata;
     831                 :            :         TransferType type;
     832                 :            :         uint32_t id;
     833                 :            : 
     834         [ #  # ]:          0 :         assert(msg);
     835         [ #  # ]:          0 :         assert(m);
     836                 :            : 
     837                 :          0 :         r = bus_verify_polkit_async(
     838                 :            :                         msg,
     839                 :            :                         CAP_SYS_ADMIN,
     840                 :            :                         "org.freedesktop.import1.export",
     841                 :            :                         NULL,
     842                 :            :                         false,
     843                 :            :                         UID_INVALID,
     844                 :            :                         &m->polkit_registry,
     845                 :            :                         error);
     846         [ #  # ]:          0 :         if (r < 0)
     847                 :          0 :                 return r;
     848         [ #  # ]:          0 :         if (r == 0)
     849                 :          0 :                 return 1; /* Will call us back */
     850                 :            : 
     851                 :          0 :         r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
     852         [ #  # ]:          0 :         if (r < 0)
     853                 :          0 :                 return r;
     854                 :            : 
     855         [ #  # ]:          0 :         if (!machine_name_is_valid(local))
     856                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
     857                 :            : 
     858                 :          0 :         r = fd_verify_regular(fd);
     859         [ #  # ]:          0 :         if (r < 0)
     860                 :          0 :                 return r;
     861                 :            : 
     862         [ #  # ]:          0 :         type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
     863                 :            : 
     864                 :          0 :         r = transfer_new(m, &t);
     865         [ #  # ]:          0 :         if (r < 0)
     866                 :          0 :                 return r;
     867                 :            : 
     868                 :          0 :         t->type = type;
     869                 :            : 
     870         [ #  # ]:          0 :         if (!isempty(format)) {
     871                 :          0 :                 t->format = strdup(format);
     872         [ #  # ]:          0 :                 if (!t->format)
     873                 :          0 :                         return -ENOMEM;
     874                 :            :         }
     875                 :            : 
     876                 :          0 :         t->local = strdup(local);
     877         [ #  # ]:          0 :         if (!t->local)
     878                 :          0 :                 return -ENOMEM;
     879                 :            : 
     880                 :          0 :         t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     881         [ #  # ]:          0 :         if (t->stdout_fd < 0)
     882                 :          0 :                 return -errno;
     883                 :            : 
     884                 :          0 :         r = transfer_start(t);
     885         [ #  # ]:          0 :         if (r < 0)
     886                 :          0 :                 return r;
     887                 :            : 
     888                 :          0 :         object = t->object_path;
     889                 :          0 :         id = t->id;
     890                 :          0 :         t = NULL;
     891                 :            : 
     892                 :          0 :         return sd_bus_reply_method_return(msg, "uo", id, object);
     893                 :            : }
     894                 :            : 
     895                 :          0 : static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
     896                 :          0 :         _cleanup_(transfer_unrefp) Transfer *t = NULL;
     897                 :            :         const char *remote, *local, *verify, *object;
     898                 :          0 :         Manager *m = userdata;
     899                 :            :         ImportVerify v;
     900                 :            :         TransferType type;
     901                 :            :         int force, r;
     902                 :            :         uint32_t id;
     903                 :            : 
     904         [ #  # ]:          0 :         assert(msg);
     905         [ #  # ]:          0 :         assert(m);
     906                 :            : 
     907                 :          0 :         r = bus_verify_polkit_async(
     908                 :            :                         msg,
     909                 :            :                         CAP_SYS_ADMIN,
     910                 :            :                         "org.freedesktop.import1.pull",
     911                 :            :                         NULL,
     912                 :            :                         false,
     913                 :            :                         UID_INVALID,
     914                 :            :                         &m->polkit_registry,
     915                 :            :                         error);
     916         [ #  # ]:          0 :         if (r < 0)
     917                 :          0 :                 return r;
     918         [ #  # ]:          0 :         if (r == 0)
     919                 :          0 :                 return 1; /* Will call us back */
     920                 :            : 
     921                 :          0 :         r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
     922         [ #  # ]:          0 :         if (r < 0)
     923                 :          0 :                 return r;
     924                 :            : 
     925         [ #  # ]:          0 :         if (!http_url_is_valid(remote))
     926                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote);
     927                 :            : 
     928         [ #  # ]:          0 :         if (isempty(local))
     929                 :          0 :                 local = NULL;
     930         [ #  # ]:          0 :         else if (!machine_name_is_valid(local))
     931                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
     932                 :            : 
     933         [ #  # ]:          0 :         if (isempty(verify))
     934                 :          0 :                 v = IMPORT_VERIFY_SIGNATURE;
     935                 :            :         else
     936                 :          0 :                 v = import_verify_from_string(verify);
     937         [ #  # ]:          0 :         if (v < 0)
     938                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
     939                 :            : 
     940                 :          0 :         r = setup_machine_directory(error);
     941         [ #  # ]:          0 :         if (r < 0)
     942                 :          0 :                 return r;
     943                 :            : 
     944         [ #  # ]:          0 :         type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
     945                 :            : 
     946         [ #  # ]:          0 :         if (manager_find(m, type, remote))
     947                 :          0 :                 return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
     948                 :            : 
     949                 :          0 :         r = transfer_new(m, &t);
     950         [ #  # ]:          0 :         if (r < 0)
     951                 :          0 :                 return r;
     952                 :            : 
     953                 :          0 :         t->type = type;
     954                 :          0 :         t->verify = v;
     955                 :          0 :         t->force_local = force;
     956                 :            : 
     957                 :          0 :         t->remote = strdup(remote);
     958         [ #  # ]:          0 :         if (!t->remote)
     959                 :          0 :                 return -ENOMEM;
     960                 :            : 
     961         [ #  # ]:          0 :         if (local) {
     962                 :          0 :                 t->local = strdup(local);
     963         [ #  # ]:          0 :                 if (!t->local)
     964                 :          0 :                         return -ENOMEM;
     965                 :            :         }
     966                 :            : 
     967                 :          0 :         r = transfer_start(t);
     968         [ #  # ]:          0 :         if (r < 0)
     969                 :          0 :                 return r;
     970                 :            : 
     971                 :          0 :         object = t->object_path;
     972                 :          0 :         id = t->id;
     973                 :          0 :         t = NULL;
     974                 :            : 
     975                 :          0 :         return sd_bus_reply_method_return(msg, "uo", id, object);
     976                 :            : }
     977                 :            : 
     978                 :          0 : static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
     979                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     980                 :          0 :         Manager *m = userdata;
     981                 :            :         Transfer *t;
     982                 :            :         Iterator i;
     983                 :            :         int r;
     984                 :            : 
     985         [ #  # ]:          0 :         assert(msg);
     986         [ #  # ]:          0 :         assert(m);
     987                 :            : 
     988                 :          0 :         r = sd_bus_message_new_method_return(msg, &reply);
     989         [ #  # ]:          0 :         if (r < 0)
     990                 :          0 :                 return r;
     991                 :            : 
     992                 :          0 :         r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
     993         [ #  # ]:          0 :         if (r < 0)
     994                 :          0 :                 return r;
     995                 :            : 
     996         [ #  # ]:          0 :         HASHMAP_FOREACH(t, m->transfers, i) {
     997                 :            : 
     998                 :          0 :                 r = sd_bus_message_append(
     999                 :            :                                 reply,
    1000                 :            :                                 "(usssdo)",
    1001                 :          0 :                                 t->id,
    1002                 :          0 :                                 transfer_type_to_string(t->type),
    1003                 :          0 :                                 t->remote,
    1004                 :          0 :                                 t->local,
    1005                 :            :                                 transfer_percent_as_double(t),
    1006                 :          0 :                                 t->object_path);
    1007         [ #  # ]:          0 :                 if (r < 0)
    1008                 :          0 :                         return r;
    1009                 :            :         }
    1010                 :            : 
    1011                 :          0 :         r = sd_bus_message_close_container(reply);
    1012         [ #  # ]:          0 :         if (r < 0)
    1013                 :          0 :                 return r;
    1014                 :            : 
    1015                 :          0 :         return sd_bus_send(NULL, reply, NULL);
    1016                 :            : }
    1017                 :            : 
    1018                 :          0 : static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
    1019                 :          0 :         Transfer *t = userdata;
    1020                 :            :         int r;
    1021                 :            : 
    1022         [ #  # ]:          0 :         assert(msg);
    1023         [ #  # ]:          0 :         assert(t);
    1024                 :            : 
    1025                 :          0 :         r = bus_verify_polkit_async(
    1026                 :            :                         msg,
    1027                 :            :                         CAP_SYS_ADMIN,
    1028                 :            :                         "org.freedesktop.import1.pull",
    1029                 :            :                         NULL,
    1030                 :            :                         false,
    1031                 :            :                         UID_INVALID,
    1032                 :          0 :                         &t->manager->polkit_registry,
    1033                 :            :                         error);
    1034         [ #  # ]:          0 :         if (r < 0)
    1035                 :          0 :                 return r;
    1036         [ #  # ]:          0 :         if (r == 0)
    1037                 :          0 :                 return 1; /* Will call us back */
    1038                 :            : 
    1039                 :          0 :         r = transfer_cancel(t);
    1040         [ #  # ]:          0 :         if (r < 0)
    1041                 :          0 :                 return r;
    1042                 :            : 
    1043                 :          0 :         return sd_bus_reply_method_return(msg, NULL);
    1044                 :            : }
    1045                 :            : 
    1046                 :          0 : static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
    1047                 :          0 :         Manager *m = userdata;
    1048                 :            :         Transfer *t;
    1049                 :            :         uint32_t id;
    1050                 :            :         int r;
    1051                 :            : 
    1052         [ #  # ]:          0 :         assert(msg);
    1053         [ #  # ]:          0 :         assert(m);
    1054                 :            : 
    1055                 :          0 :         r = bus_verify_polkit_async(
    1056                 :            :                         msg,
    1057                 :            :                         CAP_SYS_ADMIN,
    1058                 :            :                         "org.freedesktop.import1.pull",
    1059                 :            :                         NULL,
    1060                 :            :                         false,
    1061                 :            :                         UID_INVALID,
    1062                 :            :                         &m->polkit_registry,
    1063                 :            :                         error);
    1064         [ #  # ]:          0 :         if (r < 0)
    1065                 :          0 :                 return r;
    1066         [ #  # ]:          0 :         if (r == 0)
    1067                 :          0 :                 return 1; /* Will call us back */
    1068                 :            : 
    1069                 :          0 :         r = sd_bus_message_read(msg, "u", &id);
    1070         [ #  # ]:          0 :         if (r < 0)
    1071                 :          0 :                 return r;
    1072         [ #  # ]:          0 :         if (id <= 0)
    1073                 :          0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
    1074                 :            : 
    1075                 :          0 :         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
    1076         [ #  # ]:          0 :         if (!t)
    1077                 :          0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id);
    1078                 :            : 
    1079                 :          0 :         r = transfer_cancel(t);
    1080         [ #  # ]:          0 :         if (r < 0)
    1081                 :          0 :                 return r;
    1082                 :            : 
    1083                 :          0 :         return sd_bus_reply_method_return(msg, NULL);
    1084                 :            : }
    1085                 :            : 
    1086                 :          0 : static int property_get_progress(
    1087                 :            :                 sd_bus *bus,
    1088                 :            :                 const char *path,
    1089                 :            :                 const char *interface,
    1090                 :            :                 const char *property,
    1091                 :            :                 sd_bus_message *reply,
    1092                 :            :                 void *userdata,
    1093                 :            :                 sd_bus_error *error) {
    1094                 :            : 
    1095                 :          0 :         Transfer *t = userdata;
    1096                 :            : 
    1097         [ #  # ]:          0 :         assert(bus);
    1098         [ #  # ]:          0 :         assert(reply);
    1099         [ #  # ]:          0 :         assert(t);
    1100                 :            : 
    1101                 :          0 :         return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
    1102                 :            : }
    1103                 :            : 
    1104   [ #  #  #  #  :          0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
                   #  # ]
    1105   [ #  #  #  #  :          0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
                   #  # ]
    1106                 :            : 
    1107                 :            : static const sd_bus_vtable transfer_vtable[] = {
    1108                 :            :         SD_BUS_VTABLE_START(0),
    1109                 :            :         SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST),
    1110                 :            :         SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST),
    1111                 :            :         SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST),
    1112                 :            :         SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST),
    1113                 :            :         SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST),
    1114                 :            :         SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
    1115                 :            :         SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
    1116                 :            :         SD_BUS_SIGNAL("LogMessage", "us", 0),
    1117                 :            :         SD_BUS_VTABLE_END,
    1118                 :            : };
    1119                 :            : 
    1120                 :            : static const sd_bus_vtable manager_vtable[] = {
    1121                 :            :         SD_BUS_VTABLE_START(0),
    1122                 :            :         SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1123                 :            :         SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1124                 :            :         SD_BUS_METHOD("ImportFileSystem", "hsbb", "uo", method_import_fs, SD_BUS_VTABLE_UNPRIVILEGED),
    1125                 :            :         SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1126                 :            :         SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1127                 :            :         SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1128                 :            :         SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
    1129                 :            :         SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED),
    1130                 :            :         SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED),
    1131                 :            :         SD_BUS_SIGNAL("TransferNew", "uo", 0),
    1132                 :            :         SD_BUS_SIGNAL("TransferRemoved", "uos", 0),
    1133                 :            :         SD_BUS_VTABLE_END,
    1134                 :            : };
    1135                 :            : 
    1136                 :          0 : static int transfer_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
    1137                 :          0 :         Manager *m = userdata;
    1138                 :            :         Transfer *t;
    1139                 :            :         const char *p;
    1140                 :            :         uint32_t id;
    1141                 :            :         int r;
    1142                 :            : 
    1143         [ #  # ]:          0 :         assert(bus);
    1144         [ #  # ]:          0 :         assert(path);
    1145         [ #  # ]:          0 :         assert(interface);
    1146         [ #  # ]:          0 :         assert(found);
    1147         [ #  # ]:          0 :         assert(m);
    1148                 :            : 
    1149                 :          0 :         p = startswith(path, "/org/freedesktop/import1/transfer/_");
    1150         [ #  # ]:          0 :         if (!p)
    1151                 :          0 :                 return 0;
    1152                 :            : 
    1153                 :          0 :         r = safe_atou32(p, &id);
    1154   [ #  #  #  # ]:          0 :         if (r < 0 || id == 0)
    1155                 :          0 :                 return 0;
    1156                 :            : 
    1157                 :          0 :         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
    1158         [ #  # ]:          0 :         if (!t)
    1159                 :          0 :                 return 0;
    1160                 :            : 
    1161                 :          0 :         *found = t;
    1162                 :          0 :         return 1;
    1163                 :            : }
    1164                 :            : 
    1165                 :          0 : static int transfer_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
    1166                 :          0 :         _cleanup_strv_free_ char **l = NULL;
    1167                 :          0 :         Manager *m = userdata;
    1168                 :            :         Transfer *t;
    1169                 :          0 :         unsigned k = 0;
    1170                 :            :         Iterator i;
    1171                 :            : 
    1172         [ #  # ]:          0 :         l = new0(char*, hashmap_size(m->transfers) + 1);
    1173         [ #  # ]:          0 :         if (!l)
    1174                 :          0 :                 return -ENOMEM;
    1175                 :            : 
    1176         [ #  # ]:          0 :         HASHMAP_FOREACH(t, m->transfers, i) {
    1177                 :            : 
    1178                 :          0 :                 l[k] = strdup(t->object_path);
    1179         [ #  # ]:          0 :                 if (!l[k])
    1180                 :          0 :                         return -ENOMEM;
    1181                 :            : 
    1182                 :          0 :                 k++;
    1183                 :            :         }
    1184                 :            : 
    1185                 :          0 :         *nodes = TAKE_PTR(l);
    1186                 :            : 
    1187                 :          0 :         return 1;
    1188                 :            : }
    1189                 :            : 
    1190                 :          0 : static int manager_add_bus_objects(Manager *m) {
    1191                 :            :         int r;
    1192                 :            : 
    1193         [ #  # ]:          0 :         assert(m);
    1194                 :            : 
    1195                 :          0 :         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable, m);
    1196         [ #  # ]:          0 :         if (r < 0)
    1197         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to register object: %m");
    1198                 :            : 
    1199                 :          0 :         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable, transfer_object_find, m);
    1200         [ #  # ]:          0 :         if (r < 0)
    1201         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to register object: %m");
    1202                 :            : 
    1203                 :          0 :         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/import1/transfer", transfer_node_enumerator, m);
    1204         [ #  # ]:          0 :         if (r < 0)
    1205         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add transfer enumerator: %m");
    1206                 :            : 
    1207                 :          0 :         r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
    1208         [ #  # ]:          0 :         if (r < 0)
    1209         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to request name: %m");
    1210                 :            : 
    1211                 :          0 :         r = sd_bus_attach_event(m->bus, m->event, 0);
    1212         [ #  # ]:          0 :         if (r < 0)
    1213         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
    1214                 :            : 
    1215                 :          0 :         return 0;
    1216                 :            : }
    1217                 :            : 
    1218                 :          0 : static bool manager_check_idle(void *userdata) {
    1219                 :          0 :         Manager *m = userdata;
    1220                 :            : 
    1221                 :          0 :         return hashmap_isempty(m->transfers);
    1222                 :            : }
    1223                 :            : 
    1224                 :          0 : static int manager_run(Manager *m) {
    1225         [ #  # ]:          0 :         assert(m);
    1226                 :            : 
    1227                 :          0 :         return bus_event_loop_with_idle(
    1228                 :            :                         m->event,
    1229                 :            :                         m->bus,
    1230                 :            :                         "org.freedesktop.import1",
    1231                 :            :                         DEFAULT_EXIT_USEC,
    1232                 :            :                         manager_check_idle,
    1233                 :            :                         m);
    1234                 :            : }
    1235                 :            : 
    1236                 :          0 : static int run(int argc, char *argv[]) {
    1237                 :          0 :         _cleanup_(manager_unrefp) Manager *m = NULL;
    1238                 :            :         int r;
    1239                 :            : 
    1240                 :          0 :         log_setup_service();
    1241                 :            : 
    1242                 :          0 :         umask(0022);
    1243                 :            : 
    1244         [ #  # ]:          0 :         if (argc != 1) {
    1245         [ #  # ]:          0 :                 log_error("This program takes no arguments.");
    1246                 :          0 :                 return -EINVAL;
    1247                 :            :         }
    1248                 :            : 
    1249         [ #  # ]:          0 :         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
    1250                 :            : 
    1251                 :          0 :         r = manager_new(&m);
    1252         [ #  # ]:          0 :         if (r < 0)
    1253         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to allocate manager object: %m");
    1254                 :            : 
    1255                 :          0 :         r = manager_add_bus_objects(m);
    1256         [ #  # ]:          0 :         if (r < 0)
    1257                 :          0 :                 return r;
    1258                 :            : 
    1259                 :          0 :         r = manager_run(m);
    1260         [ #  # ]:          0 :         if (r < 0)
    1261         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to run event loop: %m");
    1262                 :            : 
    1263                 :          0 :         return 0;
    1264                 :            : }
    1265                 :            : 
    1266                 :          0 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14