Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
Note: File does not exist in v3.5.6.
  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
 38static int target_fd;
 39static char target_fname[W_MAX_PATH];
 40static unsigned long long filesize;
 41
 42static 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;
 96done:
 97	return error;
 98}
 99
100static 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
125static int hv_copy_finished(void)
126{
127	close(target_fd);
128	return 0;
129}
130static int hv_copy_cancel(void)
131{
132	close(target_fd);
133	unlink(target_fname);
134	return 0;
135
136}
137
138void 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
146int 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}