xref: /openbmc/linux/tools/hv/hv_fcopy_daemon.c (revision b4ed5d1682c6613988c2eb1de55df5ac9988afcc)
101325476SK. Y. Srinivasan /*
201325476SK. Y. Srinivasan  * An implementation of host to guest copy functionality for Linux.
301325476SK. Y. Srinivasan  *
401325476SK. Y. Srinivasan  * Copyright (C) 2014, Microsoft, Inc.
501325476SK. Y. Srinivasan  *
601325476SK. Y. Srinivasan  * Author : K. Y. Srinivasan <kys@microsoft.com>
701325476SK. Y. Srinivasan  *
801325476SK. Y. Srinivasan  * This program is free software; you can redistribute it and/or modify it
901325476SK. Y. Srinivasan  * under the terms of the GNU General Public License version 2 as published
1001325476SK. Y. Srinivasan  * by the Free Software Foundation.
1101325476SK. Y. Srinivasan  *
1201325476SK. Y. Srinivasan  * This program is distributed in the hope that it will be useful, but
1301325476SK. Y. Srinivasan  * WITHOUT ANY WARRANTY; without even the implied warranty of
1401325476SK. Y. Srinivasan  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
1501325476SK. Y. Srinivasan  * NON INFRINGEMENT.  See the GNU General Public License for more
1601325476SK. Y. Srinivasan  * details.
1701325476SK. Y. Srinivasan  */
1801325476SK. Y. Srinivasan 
1901325476SK. Y. Srinivasan 
2001325476SK. Y. Srinivasan #include <sys/types.h>
2101325476SK. Y. Srinivasan #include <sys/socket.h>
2201325476SK. Y. Srinivasan #include <sys/poll.h>
2301325476SK. Y. Srinivasan #include <linux/types.h>
2401325476SK. Y. Srinivasan #include <linux/kdev_t.h>
2501325476SK. Y. Srinivasan #include <stdio.h>
2601325476SK. Y. Srinivasan #include <stdlib.h>
2701325476SK. Y. Srinivasan #include <unistd.h>
2801325476SK. Y. Srinivasan #include <string.h>
2901325476SK. Y. Srinivasan #include <ctype.h>
3001325476SK. Y. Srinivasan #include <errno.h>
3101325476SK. Y. Srinivasan #include <linux/hyperv.h>
3201325476SK. Y. Srinivasan #include <syslog.h>
3301325476SK. Y. Srinivasan #include <sys/stat.h>
3401325476SK. Y. Srinivasan #include <fcntl.h>
3501325476SK. Y. Srinivasan #include <dirent.h>
36170f4beaSVitaly Kuznetsov #include <getopt.h>
3701325476SK. Y. Srinivasan 
3801325476SK. Y. Srinivasan static int target_fd;
3901325476SK. Y. Srinivasan static char target_fname[W_MAX_PATH];
40*b4ed5d16SOlaf Hering static unsigned long long filesize;
4101325476SK. Y. Srinivasan 
4201325476SK. Y. Srinivasan static int hv_start_fcopy(struct hv_start_fcopy *smsg)
4301325476SK. Y. Srinivasan {
4401325476SK. Y. Srinivasan 	int error = HV_E_FAIL;
4501325476SK. Y. Srinivasan 	char *q, *p;
4601325476SK. Y. Srinivasan 
47*b4ed5d16SOlaf Hering 	filesize = 0;
4801325476SK. Y. Srinivasan 	p = (char *)smsg->path_name;
4901325476SK. Y. Srinivasan 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
50aba474b8SVitaly Kuznetsov 		 (char *)smsg->path_name, (char *)smsg->file_name);
5101325476SK. Y. Srinivasan 
5201325476SK. Y. Srinivasan 	syslog(LOG_INFO, "Target file name: %s", target_fname);
5301325476SK. Y. Srinivasan 	/*
5401325476SK. Y. Srinivasan 	 * Check to see if the path is already in place; if not,
5501325476SK. Y. Srinivasan 	 * create if required.
5601325476SK. Y. Srinivasan 	 */
5701325476SK. Y. Srinivasan 	while ((q = strchr(p, '/')) != NULL) {
5801325476SK. Y. Srinivasan 		if (q == p) {
5901325476SK. Y. Srinivasan 			p++;
6001325476SK. Y. Srinivasan 			continue;
6101325476SK. Y. Srinivasan 		}
6201325476SK. Y. Srinivasan 		*q = '\0';
6301325476SK. Y. Srinivasan 		if (access((char *)smsg->path_name, F_OK)) {
6401325476SK. Y. Srinivasan 			if (smsg->copy_flags & CREATE_PATH) {
6501325476SK. Y. Srinivasan 				if (mkdir((char *)smsg->path_name, 0755)) {
6601325476SK. Y. Srinivasan 					syslog(LOG_ERR, "Failed to create %s",
6701325476SK. Y. Srinivasan 						(char *)smsg->path_name);
6801325476SK. Y. Srinivasan 					goto done;
6901325476SK. Y. Srinivasan 				}
7001325476SK. Y. Srinivasan 			} else {
7101325476SK. Y. Srinivasan 				syslog(LOG_ERR, "Invalid path: %s",
7201325476SK. Y. Srinivasan 					(char *)smsg->path_name);
7301325476SK. Y. Srinivasan 				goto done;
7401325476SK. Y. Srinivasan 			}
7501325476SK. Y. Srinivasan 		}
7601325476SK. Y. Srinivasan 		p = q + 1;
7701325476SK. Y. Srinivasan 		*q = '/';
7801325476SK. Y. Srinivasan 	}
7901325476SK. Y. Srinivasan 
8001325476SK. Y. Srinivasan 	if (!access(target_fname, F_OK)) {
8101325476SK. Y. Srinivasan 		syslog(LOG_INFO, "File: %s exists", target_fname);
82314672a2SK. Y. Srinivasan 		if (!(smsg->copy_flags & OVER_WRITE)) {
83314672a2SK. Y. Srinivasan 			error = HV_ERROR_ALREADY_EXISTS;
8401325476SK. Y. Srinivasan 			goto done;
8501325476SK. Y. Srinivasan 		}
86314672a2SK. Y. Srinivasan 	}
8701325476SK. Y. Srinivasan 
88e013ac31SYue Zhang 	target_fd = open(target_fname,
89e013ac31SYue Zhang 			 O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
9001325476SK. Y. Srinivasan 	if (target_fd == -1) {
9101325476SK. Y. Srinivasan 		syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
9201325476SK. Y. Srinivasan 		goto done;
9301325476SK. Y. Srinivasan 	}
9401325476SK. Y. Srinivasan 
9501325476SK. Y. Srinivasan 	error = 0;
9601325476SK. Y. Srinivasan done:
9701325476SK. Y. Srinivasan 	return error;
9801325476SK. Y. Srinivasan }
9901325476SK. Y. Srinivasan 
10001325476SK. Y. Srinivasan static int hv_copy_data(struct hv_do_fcopy *cpmsg)
10101325476SK. Y. Srinivasan {
10201325476SK. Y. Srinivasan 	ssize_t bytes_written;
103*b4ed5d16SOlaf Hering 	int ret = 0;
10401325476SK. Y. Srinivasan 
10501325476SK. Y. Srinivasan 	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
10601325476SK. Y. Srinivasan 				cpmsg->offset);
10701325476SK. Y. Srinivasan 
108*b4ed5d16SOlaf Hering 	filesize += cpmsg->size;
109*b4ed5d16SOlaf Hering 	if (bytes_written != cpmsg->size) {
110*b4ed5d16SOlaf Hering 		switch (errno) {
111*b4ed5d16SOlaf Hering 		case ENOSPC:
112*b4ed5d16SOlaf Hering 			ret = HV_ERROR_DISK_FULL;
113*b4ed5d16SOlaf Hering 			break;
114*b4ed5d16SOlaf Hering 		default:
115*b4ed5d16SOlaf Hering 			ret = HV_E_FAIL;
116*b4ed5d16SOlaf Hering 			break;
117*b4ed5d16SOlaf Hering 		}
118*b4ed5d16SOlaf Hering 		syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
119*b4ed5d16SOlaf Hering 		       filesize, (long)bytes_written, strerror(errno));
120*b4ed5d16SOlaf Hering 	}
12101325476SK. Y. Srinivasan 
122*b4ed5d16SOlaf Hering 	return ret;
12301325476SK. Y. Srinivasan }
12401325476SK. Y. Srinivasan 
12501325476SK. Y. Srinivasan static int hv_copy_finished(void)
12601325476SK. Y. Srinivasan {
12701325476SK. Y. Srinivasan 	close(target_fd);
12801325476SK. Y. Srinivasan 	return 0;
12901325476SK. Y. Srinivasan }
13001325476SK. Y. Srinivasan static int hv_copy_cancel(void)
13101325476SK. Y. Srinivasan {
13201325476SK. Y. Srinivasan 	close(target_fd);
13301325476SK. Y. Srinivasan 	unlink(target_fname);
13401325476SK. Y. Srinivasan 	return 0;
13501325476SK. Y. Srinivasan 
13601325476SK. Y. Srinivasan }
13701325476SK. Y. Srinivasan 
138170f4beaSVitaly Kuznetsov void print_usage(char *argv[])
139170f4beaSVitaly Kuznetsov {
140170f4beaSVitaly Kuznetsov 	fprintf(stderr, "Usage: %s [options]\n"
141170f4beaSVitaly Kuznetsov 		"Options are:\n"
142170f4beaSVitaly Kuznetsov 		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
143170f4beaSVitaly Kuznetsov 		"  -h, --help             print this help\n", argv[0]);
144170f4beaSVitaly Kuznetsov }
145170f4beaSVitaly Kuznetsov 
146170f4beaSVitaly Kuznetsov int main(int argc, char *argv[])
14701325476SK. Y. Srinivasan {
148aba474b8SVitaly Kuznetsov 	int fcopy_fd, len;
14901325476SK. Y. Srinivasan 	int error;
150170f4beaSVitaly Kuznetsov 	int daemonize = 1, long_index = 0, opt;
15101325476SK. Y. Srinivasan 	int version = FCOPY_CURRENT_VERSION;
15201325476SK. Y. Srinivasan 	char *buffer[4096 * 2];
15301325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *in_msg;
154a4d1ee5bSVitaly Kuznetsov 	int in_handshake = 1;
155a4d1ee5bSVitaly Kuznetsov 	__u32 kernel_modver;
15601325476SK. Y. Srinivasan 
157170f4beaSVitaly Kuznetsov 	static struct option long_options[] = {
158170f4beaSVitaly Kuznetsov 		{"help",	no_argument,	   0,  'h' },
159170f4beaSVitaly Kuznetsov 		{"no-daemon",	no_argument,	   0,  'n' },
160170f4beaSVitaly Kuznetsov 		{0,		0,		   0,  0   }
161170f4beaSVitaly Kuznetsov 	};
162170f4beaSVitaly Kuznetsov 
163170f4beaSVitaly Kuznetsov 	while ((opt = getopt_long(argc, argv, "hn", long_options,
164170f4beaSVitaly Kuznetsov 				  &long_index)) != -1) {
165170f4beaSVitaly Kuznetsov 		switch (opt) {
166170f4beaSVitaly Kuznetsov 		case 'n':
167170f4beaSVitaly Kuznetsov 			daemonize = 0;
168170f4beaSVitaly Kuznetsov 			break;
169170f4beaSVitaly Kuznetsov 		case 'h':
170170f4beaSVitaly Kuznetsov 		default:
171170f4beaSVitaly Kuznetsov 			print_usage(argv);
172170f4beaSVitaly Kuznetsov 			exit(EXIT_FAILURE);
173170f4beaSVitaly Kuznetsov 		}
174170f4beaSVitaly Kuznetsov 	}
175170f4beaSVitaly Kuznetsov 
176170f4beaSVitaly Kuznetsov 	if (daemonize && daemon(1, 0)) {
17701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
17801325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
17901325476SK. Y. Srinivasan 	}
18001325476SK. Y. Srinivasan 
18101325476SK. Y. Srinivasan 	openlog("HV_FCOPY", 0, LOG_USER);
18201325476SK. Y. Srinivasan 	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
18301325476SK. Y. Srinivasan 
18401325476SK. Y. Srinivasan 	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
18501325476SK. Y. Srinivasan 
18601325476SK. Y. Srinivasan 	if (fcopy_fd < 0) {
18701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
18801325476SK. Y. Srinivasan 			errno, strerror(errno));
18901325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
19001325476SK. Y. Srinivasan 	}
19101325476SK. Y. Srinivasan 
19201325476SK. Y. Srinivasan 	/*
19301325476SK. Y. Srinivasan 	 * Register with the kernel.
19401325476SK. Y. Srinivasan 	 */
19501325476SK. Y. Srinivasan 	if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
19601325476SK. Y. Srinivasan 		syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
19701325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
19801325476SK. Y. Srinivasan 	}
19901325476SK. Y. Srinivasan 
20001325476SK. Y. Srinivasan 	while (1) {
20101325476SK. Y. Srinivasan 		/*
20201325476SK. Y. Srinivasan 		 * In this loop we process fcopy messages after the
20301325476SK. Y. Srinivasan 		 * handshake is complete.
20401325476SK. Y. Srinivasan 		 */
20501325476SK. Y. Srinivasan 		len = pread(fcopy_fd, buffer, (4096 * 2), 0);
20601325476SK. Y. Srinivasan 		if (len < 0) {
20701325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pread failed: %s", strerror(errno));
20801325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
20901325476SK. Y. Srinivasan 		}
210a4d1ee5bSVitaly Kuznetsov 
211a4d1ee5bSVitaly Kuznetsov 		if (in_handshake) {
212a4d1ee5bSVitaly Kuznetsov 			if (len != sizeof(kernel_modver)) {
213a4d1ee5bSVitaly Kuznetsov 				syslog(LOG_ERR, "invalid version negotiation");
214a4d1ee5bSVitaly Kuznetsov 				exit(EXIT_FAILURE);
215a4d1ee5bSVitaly Kuznetsov 			}
216a4d1ee5bSVitaly Kuznetsov 			kernel_modver = *(__u32 *)buffer;
217a4d1ee5bSVitaly Kuznetsov 			in_handshake = 0;
218a4d1ee5bSVitaly Kuznetsov 			syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d",
219a4d1ee5bSVitaly Kuznetsov 			       kernel_modver);
220a4d1ee5bSVitaly Kuznetsov 			continue;
221a4d1ee5bSVitaly Kuznetsov 		}
222a4d1ee5bSVitaly Kuznetsov 
22301325476SK. Y. Srinivasan 		in_msg = (struct hv_fcopy_hdr *)buffer;
22401325476SK. Y. Srinivasan 
22501325476SK. Y. Srinivasan 		switch (in_msg->operation) {
22601325476SK. Y. Srinivasan 		case START_FILE_COPY:
22701325476SK. Y. Srinivasan 			error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
22801325476SK. Y. Srinivasan 			break;
22901325476SK. Y. Srinivasan 		case WRITE_TO_FILE:
23001325476SK. Y. Srinivasan 			error = hv_copy_data((struct hv_do_fcopy *)in_msg);
23101325476SK. Y. Srinivasan 			break;
23201325476SK. Y. Srinivasan 		case COMPLETE_FCOPY:
23301325476SK. Y. Srinivasan 			error = hv_copy_finished();
23401325476SK. Y. Srinivasan 			break;
23501325476SK. Y. Srinivasan 		case CANCEL_FCOPY:
23601325476SK. Y. Srinivasan 			error = hv_copy_cancel();
23701325476SK. Y. Srinivasan 			break;
23801325476SK. Y. Srinivasan 
23901325476SK. Y. Srinivasan 		default:
24001325476SK. Y. Srinivasan 			syslog(LOG_ERR, "Unknown operation: %d",
24101325476SK. Y. Srinivasan 				in_msg->operation);
24201325476SK. Y. Srinivasan 
24301325476SK. Y. Srinivasan 		}
24401325476SK. Y. Srinivasan 
24501325476SK. Y. Srinivasan 		if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
24601325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
24701325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
24801325476SK. Y. Srinivasan 		}
24901325476SK. Y. Srinivasan 	}
25001325476SK. Y. Srinivasan }
251