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