xref: /openbmc/linux/tools/hv/hv_fcopy_daemon.c (revision a4d1ee5b0255a135fead1d62a7fc7e6fe718b66e)
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];
4001325476SK. Y. Srinivasan 
4101325476SK. Y. Srinivasan static int hv_start_fcopy(struct hv_start_fcopy *smsg)
4201325476SK. Y. Srinivasan {
4301325476SK. Y. Srinivasan 	int error = HV_E_FAIL;
4401325476SK. Y. Srinivasan 	char *q, *p;
4501325476SK. Y. Srinivasan 
4601325476SK. Y. Srinivasan 	p = (char *)smsg->path_name;
4701325476SK. Y. Srinivasan 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
48aba474b8SVitaly Kuznetsov 		 (char *)smsg->path_name, (char *)smsg->file_name);
4901325476SK. Y. Srinivasan 
5001325476SK. Y. Srinivasan 	syslog(LOG_INFO, "Target file name: %s", target_fname);
5101325476SK. Y. Srinivasan 	/*
5201325476SK. Y. Srinivasan 	 * Check to see if the path is already in place; if not,
5301325476SK. Y. Srinivasan 	 * create if required.
5401325476SK. Y. Srinivasan 	 */
5501325476SK. Y. Srinivasan 	while ((q = strchr(p, '/')) != NULL) {
5601325476SK. Y. Srinivasan 		if (q == p) {
5701325476SK. Y. Srinivasan 			p++;
5801325476SK. Y. Srinivasan 			continue;
5901325476SK. Y. Srinivasan 		}
6001325476SK. Y. Srinivasan 		*q = '\0';
6101325476SK. Y. Srinivasan 		if (access((char *)smsg->path_name, F_OK)) {
6201325476SK. Y. Srinivasan 			if (smsg->copy_flags & CREATE_PATH) {
6301325476SK. Y. Srinivasan 				if (mkdir((char *)smsg->path_name, 0755)) {
6401325476SK. Y. Srinivasan 					syslog(LOG_ERR, "Failed to create %s",
6501325476SK. Y. Srinivasan 						(char *)smsg->path_name);
6601325476SK. Y. Srinivasan 					goto done;
6701325476SK. Y. Srinivasan 				}
6801325476SK. Y. Srinivasan 			} else {
6901325476SK. Y. Srinivasan 				syslog(LOG_ERR, "Invalid path: %s",
7001325476SK. Y. Srinivasan 					(char *)smsg->path_name);
7101325476SK. Y. Srinivasan 				goto done;
7201325476SK. Y. Srinivasan 			}
7301325476SK. Y. Srinivasan 		}
7401325476SK. Y. Srinivasan 		p = q + 1;
7501325476SK. Y. Srinivasan 		*q = '/';
7601325476SK. Y. Srinivasan 	}
7701325476SK. Y. Srinivasan 
7801325476SK. Y. Srinivasan 	if (!access(target_fname, F_OK)) {
7901325476SK. Y. Srinivasan 		syslog(LOG_INFO, "File: %s exists", target_fname);
80314672a2SK. Y. Srinivasan 		if (!(smsg->copy_flags & OVER_WRITE)) {
81314672a2SK. Y. Srinivasan 			error = HV_ERROR_ALREADY_EXISTS;
8201325476SK. Y. Srinivasan 			goto done;
8301325476SK. Y. Srinivasan 		}
84314672a2SK. Y. Srinivasan 	}
8501325476SK. Y. Srinivasan 
86e013ac31SYue Zhang 	target_fd = open(target_fname,
87e013ac31SYue Zhang 			 O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
8801325476SK. Y. Srinivasan 	if (target_fd == -1) {
8901325476SK. Y. Srinivasan 		syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
9001325476SK. Y. Srinivasan 		goto done;
9101325476SK. Y. Srinivasan 	}
9201325476SK. Y. Srinivasan 
9301325476SK. Y. Srinivasan 	error = 0;
9401325476SK. Y. Srinivasan done:
9501325476SK. Y. Srinivasan 	return error;
9601325476SK. Y. Srinivasan }
9701325476SK. Y. Srinivasan 
9801325476SK. Y. Srinivasan static int hv_copy_data(struct hv_do_fcopy *cpmsg)
9901325476SK. Y. Srinivasan {
10001325476SK. Y. Srinivasan 	ssize_t bytes_written;
10101325476SK. Y. Srinivasan 
10201325476SK. Y. Srinivasan 	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
10301325476SK. Y. Srinivasan 				cpmsg->offset);
10401325476SK. Y. Srinivasan 
10501325476SK. Y. Srinivasan 	if (bytes_written != cpmsg->size)
10601325476SK. Y. Srinivasan 		return HV_E_FAIL;
10701325476SK. Y. Srinivasan 
10801325476SK. Y. Srinivasan 	return 0;
10901325476SK. Y. Srinivasan }
11001325476SK. Y. Srinivasan 
11101325476SK. Y. Srinivasan static int hv_copy_finished(void)
11201325476SK. Y. Srinivasan {
11301325476SK. Y. Srinivasan 	close(target_fd);
11401325476SK. Y. Srinivasan 	return 0;
11501325476SK. Y. Srinivasan }
11601325476SK. Y. Srinivasan static int hv_copy_cancel(void)
11701325476SK. Y. Srinivasan {
11801325476SK. Y. Srinivasan 	close(target_fd);
11901325476SK. Y. Srinivasan 	unlink(target_fname);
12001325476SK. Y. Srinivasan 	return 0;
12101325476SK. Y. Srinivasan 
12201325476SK. Y. Srinivasan }
12301325476SK. Y. Srinivasan 
124170f4beaSVitaly Kuznetsov void print_usage(char *argv[])
125170f4beaSVitaly Kuznetsov {
126170f4beaSVitaly Kuznetsov 	fprintf(stderr, "Usage: %s [options]\n"
127170f4beaSVitaly Kuznetsov 		"Options are:\n"
128170f4beaSVitaly Kuznetsov 		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
129170f4beaSVitaly Kuznetsov 		"  -h, --help             print this help\n", argv[0]);
130170f4beaSVitaly Kuznetsov }
131170f4beaSVitaly Kuznetsov 
132170f4beaSVitaly Kuznetsov int main(int argc, char *argv[])
13301325476SK. Y. Srinivasan {
134aba474b8SVitaly Kuznetsov 	int fcopy_fd, len;
13501325476SK. Y. Srinivasan 	int error;
136170f4beaSVitaly Kuznetsov 	int daemonize = 1, long_index = 0, opt;
13701325476SK. Y. Srinivasan 	int version = FCOPY_CURRENT_VERSION;
13801325476SK. Y. Srinivasan 	char *buffer[4096 * 2];
13901325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *in_msg;
140*a4d1ee5bSVitaly Kuznetsov 	int in_handshake = 1;
141*a4d1ee5bSVitaly Kuznetsov 	__u32 kernel_modver;
14201325476SK. Y. Srinivasan 
143170f4beaSVitaly Kuznetsov 	static struct option long_options[] = {
144170f4beaSVitaly Kuznetsov 		{"help",	no_argument,	   0,  'h' },
145170f4beaSVitaly Kuznetsov 		{"no-daemon",	no_argument,	   0,  'n' },
146170f4beaSVitaly Kuznetsov 		{0,		0,		   0,  0   }
147170f4beaSVitaly Kuznetsov 	};
148170f4beaSVitaly Kuznetsov 
149170f4beaSVitaly Kuznetsov 	while ((opt = getopt_long(argc, argv, "hn", long_options,
150170f4beaSVitaly Kuznetsov 				  &long_index)) != -1) {
151170f4beaSVitaly Kuznetsov 		switch (opt) {
152170f4beaSVitaly Kuznetsov 		case 'n':
153170f4beaSVitaly Kuznetsov 			daemonize = 0;
154170f4beaSVitaly Kuznetsov 			break;
155170f4beaSVitaly Kuznetsov 		case 'h':
156170f4beaSVitaly Kuznetsov 		default:
157170f4beaSVitaly Kuznetsov 			print_usage(argv);
158170f4beaSVitaly Kuznetsov 			exit(EXIT_FAILURE);
159170f4beaSVitaly Kuznetsov 		}
160170f4beaSVitaly Kuznetsov 	}
161170f4beaSVitaly Kuznetsov 
162170f4beaSVitaly Kuznetsov 	if (daemonize && daemon(1, 0)) {
16301325476SK. Y. Srinivasan 		syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
16401325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
16501325476SK. Y. Srinivasan 	}
16601325476SK. Y. Srinivasan 
16701325476SK. Y. Srinivasan 	openlog("HV_FCOPY", 0, LOG_USER);
16801325476SK. Y. Srinivasan 	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
16901325476SK. Y. Srinivasan 
17001325476SK. Y. Srinivasan 	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
17101325476SK. Y. Srinivasan 
17201325476SK. Y. Srinivasan 	if (fcopy_fd < 0) {
17301325476SK. Y. Srinivasan 		syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
17401325476SK. Y. Srinivasan 			errno, strerror(errno));
17501325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
17601325476SK. Y. Srinivasan 	}
17701325476SK. Y. Srinivasan 
17801325476SK. Y. Srinivasan 	/*
17901325476SK. Y. Srinivasan 	 * Register with the kernel.
18001325476SK. Y. Srinivasan 	 */
18101325476SK. Y. Srinivasan 	if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
18201325476SK. Y. Srinivasan 		syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
18301325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
18401325476SK. Y. Srinivasan 	}
18501325476SK. Y. Srinivasan 
18601325476SK. Y. Srinivasan 	while (1) {
18701325476SK. Y. Srinivasan 		/*
18801325476SK. Y. Srinivasan 		 * In this loop we process fcopy messages after the
18901325476SK. Y. Srinivasan 		 * handshake is complete.
19001325476SK. Y. Srinivasan 		 */
19101325476SK. Y. Srinivasan 		len = pread(fcopy_fd, buffer, (4096 * 2), 0);
19201325476SK. Y. Srinivasan 		if (len < 0) {
19301325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pread failed: %s", strerror(errno));
19401325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
19501325476SK. Y. Srinivasan 		}
196*a4d1ee5bSVitaly Kuznetsov 
197*a4d1ee5bSVitaly Kuznetsov 		if (in_handshake) {
198*a4d1ee5bSVitaly Kuznetsov 			if (len != sizeof(kernel_modver)) {
199*a4d1ee5bSVitaly Kuznetsov 				syslog(LOG_ERR, "invalid version negotiation");
200*a4d1ee5bSVitaly Kuznetsov 				exit(EXIT_FAILURE);
201*a4d1ee5bSVitaly Kuznetsov 			}
202*a4d1ee5bSVitaly Kuznetsov 			kernel_modver = *(__u32 *)buffer;
203*a4d1ee5bSVitaly Kuznetsov 			in_handshake = 0;
204*a4d1ee5bSVitaly Kuznetsov 			syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d",
205*a4d1ee5bSVitaly Kuznetsov 			       kernel_modver);
206*a4d1ee5bSVitaly Kuznetsov 			continue;
207*a4d1ee5bSVitaly Kuznetsov 		}
208*a4d1ee5bSVitaly Kuznetsov 
20901325476SK. Y. Srinivasan 		in_msg = (struct hv_fcopy_hdr *)buffer;
21001325476SK. Y. Srinivasan 
21101325476SK. Y. Srinivasan 		switch (in_msg->operation) {
21201325476SK. Y. Srinivasan 		case START_FILE_COPY:
21301325476SK. Y. Srinivasan 			error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
21401325476SK. Y. Srinivasan 			break;
21501325476SK. Y. Srinivasan 		case WRITE_TO_FILE:
21601325476SK. Y. Srinivasan 			error = hv_copy_data((struct hv_do_fcopy *)in_msg);
21701325476SK. Y. Srinivasan 			break;
21801325476SK. Y. Srinivasan 		case COMPLETE_FCOPY:
21901325476SK. Y. Srinivasan 			error = hv_copy_finished();
22001325476SK. Y. Srinivasan 			break;
22101325476SK. Y. Srinivasan 		case CANCEL_FCOPY:
22201325476SK. Y. Srinivasan 			error = hv_copy_cancel();
22301325476SK. Y. Srinivasan 			break;
22401325476SK. Y. Srinivasan 
22501325476SK. Y. Srinivasan 		default:
22601325476SK. Y. Srinivasan 			syslog(LOG_ERR, "Unknown operation: %d",
22701325476SK. Y. Srinivasan 				in_msg->operation);
22801325476SK. Y. Srinivasan 
22901325476SK. Y. Srinivasan 		}
23001325476SK. Y. Srinivasan 
23101325476SK. Y. Srinivasan 		if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
23201325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
23301325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
23401325476SK. Y. Srinivasan 		}
23501325476SK. Y. Srinivasan 	}
23601325476SK. Y. Srinivasan }
237