root/tools/hv/hv_fcopy_daemon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hv_start_fcopy
  2. hv_copy_data
  3. hv_copy_finished
  4. hv_copy_cancel
  5. print_usage
  6. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * An implementation of host to guest copy functionality for Linux.
   4  *
   5  * Copyright (C) 2014, Microsoft, Inc.
   6  *
   7  * Author : K. Y. Srinivasan <kys@microsoft.com>
   8  */
   9 
  10 
  11 #include <sys/types.h>
  12 #include <stdio.h>
  13 #include <stdlib.h>
  14 #include <unistd.h>
  15 #include <string.h>
  16 #include <errno.h>
  17 #include <linux/hyperv.h>
  18 #include <linux/limits.h>
  19 #include <syslog.h>
  20 #include <sys/stat.h>
  21 #include <fcntl.h>
  22 #include <getopt.h>
  23 
  24 static int target_fd;
  25 static char target_fname[PATH_MAX];
  26 static unsigned long long filesize;
  27 
  28 static int hv_start_fcopy(struct hv_start_fcopy *smsg)
  29 {
  30         int error = HV_E_FAIL;
  31         char *q, *p;
  32 
  33         filesize = 0;
  34         p = (char *)smsg->path_name;
  35         snprintf(target_fname, sizeof(target_fname), "%s/%s",
  36                  (char *)smsg->path_name, (char *)smsg->file_name);
  37 
  38         syslog(LOG_INFO, "Target file name: %s", target_fname);
  39         /*
  40          * Check to see if the path is already in place; if not,
  41          * create if required.
  42          */
  43         while ((q = strchr(p, '/')) != NULL) {
  44                 if (q == p) {
  45                         p++;
  46                         continue;
  47                 }
  48                 *q = '\0';
  49                 if (access((char *)smsg->path_name, F_OK)) {
  50                         if (smsg->copy_flags & CREATE_PATH) {
  51                                 if (mkdir((char *)smsg->path_name, 0755)) {
  52                                         syslog(LOG_ERR, "Failed to create %s",
  53                                                 (char *)smsg->path_name);
  54                                         goto done;
  55                                 }
  56                         } else {
  57                                 syslog(LOG_ERR, "Invalid path: %s",
  58                                         (char *)smsg->path_name);
  59                                 goto done;
  60                         }
  61                 }
  62                 p = q + 1;
  63                 *q = '/';
  64         }
  65 
  66         if (!access(target_fname, F_OK)) {
  67                 syslog(LOG_INFO, "File: %s exists", target_fname);
  68                 if (!(smsg->copy_flags & OVER_WRITE)) {
  69                         error = HV_ERROR_ALREADY_EXISTS;
  70                         goto done;
  71                 }
  72         }
  73 
  74         target_fd = open(target_fname,
  75                          O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
  76         if (target_fd == -1) {
  77                 syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
  78                 goto done;
  79         }
  80 
  81         error = 0;
  82 done:
  83         return error;
  84 }
  85 
  86 static int hv_copy_data(struct hv_do_fcopy *cpmsg)
  87 {
  88         ssize_t bytes_written;
  89         int ret = 0;
  90 
  91         bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
  92                                 cpmsg->offset);
  93 
  94         filesize += cpmsg->size;
  95         if (bytes_written != cpmsg->size) {
  96                 switch (errno) {
  97                 case ENOSPC:
  98                         ret = HV_ERROR_DISK_FULL;
  99                         break;
 100                 default:
 101                         ret = HV_E_FAIL;
 102                         break;
 103                 }
 104                 syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
 105                        filesize, (long)bytes_written, strerror(errno));
 106         }
 107 
 108         return ret;
 109 }
 110 
 111 static int hv_copy_finished(void)
 112 {
 113         close(target_fd);
 114         return 0;
 115 }
 116 static int hv_copy_cancel(void)
 117 {
 118         close(target_fd);
 119         unlink(target_fname);
 120         return 0;
 121 
 122 }
 123 
 124 void print_usage(char *argv[])
 125 {
 126         fprintf(stderr, "Usage: %s [options]\n"
 127                 "Options are:\n"
 128                 "  -n, --no-daemon        stay in foreground, don't daemonize\n"
 129                 "  -h, --help             print this help\n", argv[0]);
 130 }
 131 
 132 int main(int argc, char *argv[])
 133 {
 134         int fcopy_fd;
 135         int error;
 136         int daemonize = 1, long_index = 0, opt;
 137         int version = FCOPY_CURRENT_VERSION;
 138         union {
 139                 struct hv_fcopy_hdr hdr;
 140                 struct hv_start_fcopy start;
 141                 struct hv_do_fcopy copy;
 142                 __u32 kernel_modver;
 143         } buffer = { };
 144         int in_handshake = 1;
 145 
 146         static struct option long_options[] = {
 147                 {"help",        no_argument,       0,  'h' },
 148                 {"no-daemon",   no_argument,       0,  'n' },
 149                 {0,             0,                 0,  0   }
 150         };
 151 
 152         while ((opt = getopt_long(argc, argv, "hn", long_options,
 153                                   &long_index)) != -1) {
 154                 switch (opt) {
 155                 case 'n':
 156                         daemonize = 0;
 157                         break;
 158                 case 'h':
 159                 default:
 160                         print_usage(argv);
 161                         exit(EXIT_FAILURE);
 162                 }
 163         }
 164 
 165         if (daemonize && daemon(1, 0)) {
 166                 syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
 167                 exit(EXIT_FAILURE);
 168         }
 169 
 170         openlog("HV_FCOPY", 0, LOG_USER);
 171         syslog(LOG_INFO, "starting; pid is:%d", getpid());
 172 
 173         fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
 174 
 175         if (fcopy_fd < 0) {
 176                 syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
 177                         errno, strerror(errno));
 178                 exit(EXIT_FAILURE);
 179         }
 180 
 181         /*
 182          * Register with the kernel.
 183          */
 184         if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
 185                 syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
 186                 exit(EXIT_FAILURE);
 187         }
 188 
 189         while (1) {
 190                 /*
 191                  * In this loop we process fcopy messages after the
 192                  * handshake is complete.
 193                  */
 194                 ssize_t len;
 195 
 196                 len = pread(fcopy_fd, &buffer, sizeof(buffer), 0);
 197                 if (len < 0) {
 198                         syslog(LOG_ERR, "pread failed: %s", strerror(errno));
 199                         exit(EXIT_FAILURE);
 200                 }
 201 
 202                 if (in_handshake) {
 203                         if (len != sizeof(buffer.kernel_modver)) {
 204                                 syslog(LOG_ERR, "invalid version negotiation");
 205                                 exit(EXIT_FAILURE);
 206                         }
 207                         in_handshake = 0;
 208                         syslog(LOG_INFO, "kernel module version: %u",
 209                                buffer.kernel_modver);
 210                         continue;
 211                 }
 212 
 213                 switch (buffer.hdr.operation) {
 214                 case START_FILE_COPY:
 215                         error = hv_start_fcopy(&buffer.start);
 216                         break;
 217                 case WRITE_TO_FILE:
 218                         error = hv_copy_data(&buffer.copy);
 219                         break;
 220                 case COMPLETE_FCOPY:
 221                         error = hv_copy_finished();
 222                         break;
 223                 case CANCEL_FCOPY:
 224                         error = hv_copy_cancel();
 225                         break;
 226 
 227                 default:
 228                         error = HV_E_FAIL;
 229                         syslog(LOG_ERR, "Unknown operation: %d",
 230                                 buffer.hdr.operation);
 231 
 232                 }
 233 
 234                 if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
 235                         syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
 236                         exit(EXIT_FAILURE);
 237                 }
 238         }
 239 }

/* [<][>][^][v][top][bottom][index][help] */