Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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