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