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