LCOV - code coverage report
Current view: top level - import - export.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 20 161 12.4 %
Date: 2019-08-22 15:41:25 Functions: 4 11 36.4 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : #include <locale.h>
       5             : 
       6             : #include "sd-event.h"
       7             : #include "sd-id128.h"
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "export-raw.h"
      11             : #include "export-tar.h"
      12             : #include "fd-util.h"
      13             : #include "fs-util.h"
      14             : #include "hostname-util.h"
      15             : #include "import-util.h"
      16             : #include "machine-image.h"
      17             : #include "main-func.h"
      18             : #include "signal-util.h"
      19             : #include "string-util.h"
      20             : #include "verbs.h"
      21             : 
      22             : static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
      23             : 
      24           0 : static void determine_compression_from_filename(const char *p) {
      25             : 
      26           0 :         if (arg_compress != IMPORT_COMPRESS_UNKNOWN)
      27           0 :                 return;
      28             : 
      29           0 :         if (!p) {
      30           0 :                 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
      31           0 :                 return;
      32             :         }
      33             : 
      34           0 :         if (endswith(p, ".xz"))
      35           0 :                 arg_compress = IMPORT_COMPRESS_XZ;
      36           0 :         else if (endswith(p, ".gz"))
      37           0 :                 arg_compress = IMPORT_COMPRESS_GZIP;
      38           0 :         else if (endswith(p, ".bz2"))
      39           0 :                 arg_compress = IMPORT_COMPRESS_BZIP2;
      40             :         else
      41           0 :                 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
      42             : }
      43             : 
      44           0 : static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
      45           0 :         log_notice("Transfer aborted.");
      46           0 :         sd_event_exit(sd_event_source_get_event(s), EINTR);
      47           0 :         return 0;
      48             : }
      49             : 
      50           0 : static void on_tar_finished(TarExport *export, int error, void *userdata) {
      51           0 :         sd_event *event = userdata;
      52           0 :         assert(export);
      53             : 
      54           0 :         if (error == 0)
      55           0 :                 log_info("Operation completed successfully.");
      56             : 
      57           0 :         sd_event_exit(event, abs(error));
      58           0 : }
      59             : 
      60           0 : static int export_tar(int argc, char *argv[], void *userdata) {
      61           0 :         _cleanup_(tar_export_unrefp) TarExport *export = NULL;
      62           0 :         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
      63           0 :         _cleanup_(image_unrefp) Image *image = NULL;
      64           0 :         const char *path = NULL, *local = NULL;
      65           0 :         _cleanup_close_ int open_fd = -1;
      66             :         int r, fd;
      67             : 
      68           0 :         if (machine_name_is_valid(argv[1])) {
      69           0 :                 r = image_find(IMAGE_MACHINE, argv[1], &image);
      70           0 :                 if (r == -ENOENT)
      71           0 :                         return log_error_errno(r, "Machine image %s not found.", argv[1]);
      72           0 :                 if (r < 0)
      73           0 :                         return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
      74             : 
      75           0 :                 local = image->path;
      76             :         } else
      77           0 :                 local = argv[1];
      78             : 
      79           0 :         if (argc >= 3)
      80           0 :                 path = argv[2];
      81           0 :         path = empty_or_dash_to_null(path);
      82             : 
      83           0 :         determine_compression_from_filename(path);
      84             : 
      85           0 :         if (path) {
      86           0 :                 open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
      87           0 :                 if (open_fd < 0)
      88           0 :                         return log_error_errno(errno, "Failed to open tar image for export: %m");
      89             : 
      90           0 :                 fd = open_fd;
      91             : 
      92           0 :                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
      93             :         } else {
      94           0 :                 _cleanup_free_ char *pretty = NULL;
      95             : 
      96           0 :                 fd = STDOUT_FILENO;
      97             : 
      98           0 :                 (void) fd_get_path(fd, &pretty);
      99           0 :                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
     100             :         }
     101             : 
     102           0 :         r = sd_event_default(&event);
     103           0 :         if (r < 0)
     104           0 :                 return log_error_errno(r, "Failed to allocate event loop: %m");
     105             : 
     106           0 :         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
     107           0 :         (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler,  NULL);
     108           0 :         (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
     109             : 
     110           0 :         r = tar_export_new(&export, event, on_tar_finished, event);
     111           0 :         if (r < 0)
     112           0 :                 return log_error_errno(r, "Failed to allocate exporter: %m");
     113             : 
     114           0 :         r = tar_export_start(export, local, fd, arg_compress);
     115           0 :         if (r < 0)
     116           0 :                 return log_error_errno(r, "Failed to export image: %m");
     117             : 
     118           0 :         r = sd_event_loop(event);
     119           0 :         if (r < 0)
     120           0 :                 return log_error_errno(r, "Failed to run event loop: %m");
     121             : 
     122           0 :         log_info("Exiting.");
     123           0 :         return -r;
     124             : }
     125             : 
     126           0 : static void on_raw_finished(RawExport *export, int error, void *userdata) {
     127           0 :         sd_event *event = userdata;
     128           0 :         assert(export);
     129             : 
     130           0 :         if (error == 0)
     131           0 :                 log_info("Operation completed successfully.");
     132             : 
     133           0 :         sd_event_exit(event, abs(error));
     134           0 : }
     135             : 
     136           0 : static int export_raw(int argc, char *argv[], void *userdata) {
     137           0 :         _cleanup_(raw_export_unrefp) RawExport *export = NULL;
     138           0 :         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
     139           0 :         _cleanup_(image_unrefp) Image *image = NULL;
     140           0 :         const char *path = NULL, *local = NULL;
     141           0 :         _cleanup_close_ int open_fd = -1;
     142             :         int r, fd;
     143             : 
     144           0 :         if (machine_name_is_valid(argv[1])) {
     145           0 :                 r = image_find(IMAGE_MACHINE, argv[1], &image);
     146           0 :                 if (r == -ENOENT)
     147           0 :                         return log_error_errno(r, "Machine image %s not found.", argv[1]);
     148           0 :                 if (r < 0)
     149           0 :                         return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
     150             : 
     151           0 :                 local = image->path;
     152             :         } else
     153           0 :                 local = argv[1];
     154             : 
     155           0 :         if (argc >= 3)
     156           0 :                 path = argv[2];
     157           0 :         path = empty_or_dash_to_null(path);
     158             : 
     159           0 :         determine_compression_from_filename(path);
     160             : 
     161           0 :         if (path) {
     162           0 :                 open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
     163           0 :                 if (open_fd < 0)
     164           0 :                         return log_error_errno(errno, "Failed to open raw image for export: %m");
     165             : 
     166           0 :                 fd = open_fd;
     167             : 
     168           0 :                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
     169             :         } else {
     170           0 :                 _cleanup_free_ char *pretty = NULL;
     171             : 
     172           0 :                 fd = STDOUT_FILENO;
     173             : 
     174           0 :                 (void) fd_get_path(fd, &pretty);
     175           0 :                 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
     176             :         }
     177             : 
     178           0 :         r = sd_event_default(&event);
     179           0 :         if (r < 0)
     180           0 :                 return log_error_errno(r, "Failed to allocate event loop: %m");
     181             : 
     182           0 :         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
     183           0 :         (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler,  NULL);
     184           0 :         (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
     185             : 
     186           0 :         r = raw_export_new(&export, event, on_raw_finished, event);
     187           0 :         if (r < 0)
     188           0 :                 return log_error_errno(r, "Failed to allocate exporter: %m");
     189             : 
     190           0 :         r = raw_export_start(export, local, fd, arg_compress);
     191           0 :         if (r < 0)
     192           0 :                 return log_error_errno(r, "Failed to export image: %m");
     193             : 
     194           0 :         r = sd_event_loop(event);
     195           0 :         if (r < 0)
     196           0 :                 return log_error_errno(r, "Failed to run event loop: %m");
     197             : 
     198           0 :         log_info("Exiting.");
     199           0 :         return -r;
     200             : }
     201             : 
     202           3 : static int help(int argc, char *argv[], void *userdata) {
     203             : 
     204           3 :         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
     205             :                "Export container or virtual machine images.\n\n"
     206             :                "  -h --help                    Show this help\n"
     207             :                "     --version                 Show package version\n"
     208             :                "     --format=FORMAT           Select format\n\n"
     209             :                "Commands:\n"
     210             :                "  tar NAME [FILE]              Export a TAR image\n"
     211             :                "  raw NAME [FILE]              Export a RAW image\n",
     212             :                program_invocation_short_name);
     213             : 
     214           3 :         return 0;
     215             : }
     216             : 
     217           4 : static int parse_argv(int argc, char *argv[]) {
     218             : 
     219             :         enum {
     220             :                 ARG_VERSION = 0x100,
     221             :                 ARG_FORMAT,
     222             :         };
     223             : 
     224             :         static const struct option options[] = {
     225             :                 { "help",    no_argument,       NULL, 'h'         },
     226             :                 { "version", no_argument,       NULL, ARG_VERSION },
     227             :                 { "format",  required_argument, NULL, ARG_FORMAT  },
     228             :                 {}
     229             :         };
     230             : 
     231             :         int c;
     232             : 
     233           4 :         assert(argc >= 0);
     234           4 :         assert(argv);
     235             : 
     236           4 :         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
     237             : 
     238           4 :                 switch (c) {
     239             : 
     240           3 :                 case 'h':
     241           3 :                         return help(0, NULL, NULL);
     242             : 
     243           0 :                 case ARG_VERSION:
     244           0 :                         return version();
     245             : 
     246           0 :                 case ARG_FORMAT:
     247           0 :                         if (streq(optarg, "uncompressed"))
     248           0 :                                 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
     249           0 :                         else if (streq(optarg, "xz"))
     250           0 :                                 arg_compress = IMPORT_COMPRESS_XZ;
     251           0 :                         else if (streq(optarg, "gzip"))
     252           0 :                                 arg_compress = IMPORT_COMPRESS_GZIP;
     253           0 :                         else if (streq(optarg, "bzip2"))
     254           0 :                                 arg_compress = IMPORT_COMPRESS_BZIP2;
     255             :                         else
     256           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     257             :                                                        "Unknown format: %s", optarg);
     258           0 :                         break;
     259             : 
     260           1 :                 case '?':
     261           1 :                         return -EINVAL;
     262             : 
     263           0 :                 default:
     264           0 :                         assert_not_reached("Unhandled option");
     265             :                 }
     266             : 
     267           0 :         return 1;
     268             : }
     269             : 
     270           0 : static int export_main(int argc, char *argv[]) {
     271             :         static const Verb verbs[] = {
     272             :                 { "help", VERB_ANY, VERB_ANY, 0, help       },
     273             :                 { "tar",  2,        3,        0, export_tar },
     274             :                 { "raw",  2,        3,        0, export_raw },
     275             :                 {}
     276             :         };
     277             : 
     278           0 :         return dispatch_verb(argc, argv, verbs, NULL);
     279             : }
     280             : 
     281           4 : static int run(int argc, char *argv[]) {
     282             :         int r;
     283             : 
     284           4 :         setlocale(LC_ALL, "");
     285           4 :         log_parse_environment();
     286           4 :         log_open();
     287             : 
     288           4 :         r = parse_argv(argc, argv);
     289           4 :         if (r <= 0)
     290           4 :                 return r;
     291             : 
     292           0 :         (void) ignore_signals(SIGPIPE, -1);
     293             : 
     294           0 :         return export_main(argc, argv);
     295             : }
     296             : 
     297           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14