xref: /openbmc/linux/tools/hv/hv_fcopy_daemon.c (revision 170f4bea2008054e5098f99359e29823a7b4b1b9)
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>
36*170f4beaSVitaly 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 	/*
4701325476SK. Y. Srinivasan 	 * If possile append a path seperator to the path.
4801325476SK. Y. Srinivasan 	 */
4901325476SK. Y. Srinivasan 	if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
5001325476SK. Y. Srinivasan 		strcat((char *)smsg->path_name, "/");
5101325476SK. Y. Srinivasan 
5201325476SK. Y. Srinivasan 	p = (char *)smsg->path_name;
5301325476SK. Y. Srinivasan 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
5401325476SK. Y. Srinivasan 		(char *)smsg->path_name, smsg->file_name);
5501325476SK. Y. Srinivasan 
5601325476SK. Y. Srinivasan 	syslog(LOG_INFO, "Target file name: %s", target_fname);
5701325476SK. Y. Srinivasan 	/*
5801325476SK. Y. Srinivasan 	 * Check to see if the path is already in place; if not,
5901325476SK. Y. Srinivasan 	 * create if required.
6001325476SK. Y. Srinivasan 	 */
6101325476SK. Y. Srinivasan 	while ((q = strchr(p, '/')) != NULL) {
6201325476SK. Y. Srinivasan 		if (q == p) {
6301325476SK. Y. Srinivasan 			p++;
6401325476SK. Y. Srinivasan 			continue;
6501325476SK. Y. Srinivasan 		}
6601325476SK. Y. Srinivasan 		*q = '\0';
6701325476SK. Y. Srinivasan 		if (access((char *)smsg->path_name, F_OK)) {
6801325476SK. Y. Srinivasan 			if (smsg->copy_flags & CREATE_PATH) {
6901325476SK. Y. Srinivasan 				if (mkdir((char *)smsg->path_name, 0755)) {
7001325476SK. Y. Srinivasan 					syslog(LOG_ERR, "Failed to create %s",
7101325476SK. Y. Srinivasan 						(char *)smsg->path_name);
7201325476SK. Y. Srinivasan 					goto done;
7301325476SK. Y. Srinivasan 				}
7401325476SK. Y. Srinivasan 			} else {
7501325476SK. Y. Srinivasan 				syslog(LOG_ERR, "Invalid path: %s",
7601325476SK. Y. Srinivasan 					(char *)smsg->path_name);
7701325476SK. Y. Srinivasan 				goto done;
7801325476SK. Y. Srinivasan 			}
7901325476SK. Y. Srinivasan 		}
8001325476SK. Y. Srinivasan 		p = q + 1;
8101325476SK. Y. Srinivasan 		*q = '/';
8201325476SK. Y. Srinivasan 	}
8301325476SK. Y. Srinivasan 
8401325476SK. Y. Srinivasan 	if (!access(target_fname, F_OK)) {
8501325476SK. Y. Srinivasan 		syslog(LOG_INFO, "File: %s exists", target_fname);
86314672a2SK. Y. Srinivasan 		if (!(smsg->copy_flags & OVER_WRITE)) {
87314672a2SK. Y. Srinivasan 			error = HV_ERROR_ALREADY_EXISTS;
8801325476SK. Y. Srinivasan 			goto done;
8901325476SK. Y. Srinivasan 		}
90314672a2SK. Y. Srinivasan 	}
9101325476SK. Y. Srinivasan 
92e013ac31SYue Zhang 	target_fd = open(target_fname,
93e013ac31SYue Zhang 			 O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744);
9401325476SK. Y. Srinivasan 	if (target_fd == -1) {
9501325476SK. Y. Srinivasan 		syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
9601325476SK. Y. Srinivasan 		goto done;
9701325476SK. Y. Srinivasan 	}
9801325476SK. Y. Srinivasan 
9901325476SK. Y. Srinivasan 	error = 0;
10001325476SK. Y. Srinivasan done:
10101325476SK. Y. Srinivasan 	return error;
10201325476SK. Y. Srinivasan }
10301325476SK. Y. Srinivasan 
10401325476SK. Y. Srinivasan static int hv_copy_data(struct hv_do_fcopy *cpmsg)
10501325476SK. Y. Srinivasan {
10601325476SK. Y. Srinivasan 	ssize_t bytes_written;
10701325476SK. Y. Srinivasan 
10801325476SK. Y. Srinivasan 	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
10901325476SK. Y. Srinivasan 				cpmsg->offset);
11001325476SK. Y. Srinivasan 
11101325476SK. Y. Srinivasan 	if (bytes_written != cpmsg->size)
11201325476SK. Y. Srinivasan 		return HV_E_FAIL;
11301325476SK. Y. Srinivasan 
11401325476SK. Y. Srinivasan 	return 0;
11501325476SK. Y. Srinivasan }
11601325476SK. Y. Srinivasan 
11701325476SK. Y. Srinivasan static int hv_copy_finished(void)
11801325476SK. Y. Srinivasan {
11901325476SK. Y. Srinivasan 	close(target_fd);
12001325476SK. Y. Srinivasan 	return 0;
12101325476SK. Y. Srinivasan }
12201325476SK. Y. Srinivasan static int hv_copy_cancel(void)
12301325476SK. Y. Srinivasan {
12401325476SK. Y. Srinivasan 	close(target_fd);
12501325476SK. Y. Srinivasan 	unlink(target_fname);
12601325476SK. Y. Srinivasan 	return 0;
12701325476SK. Y. Srinivasan 
12801325476SK. Y. Srinivasan }
12901325476SK. Y. Srinivasan 
130*170f4beaSVitaly Kuznetsov void print_usage(char *argv[])
131*170f4beaSVitaly Kuznetsov {
132*170f4beaSVitaly Kuznetsov 	fprintf(stderr, "Usage: %s [options]\n"
133*170f4beaSVitaly Kuznetsov 		"Options are:\n"
134*170f4beaSVitaly Kuznetsov 		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
135*170f4beaSVitaly Kuznetsov 		"  -h, --help             print this help\n", argv[0]);
136*170f4beaSVitaly Kuznetsov }
137*170f4beaSVitaly Kuznetsov 
138*170f4beaSVitaly Kuznetsov int main(int argc, char *argv[])
13901325476SK. Y. Srinivasan {
14001325476SK. Y. Srinivasan 	int fd, fcopy_fd, len;
14101325476SK. Y. Srinivasan 	int error;
142*170f4beaSVitaly Kuznetsov 	int daemonize = 1, long_index = 0, opt;
14301325476SK. Y. Srinivasan 	int version = FCOPY_CURRENT_VERSION;
14401325476SK. Y. Srinivasan 	char *buffer[4096 * 2];
14501325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *in_msg;
14601325476SK. Y. Srinivasan 
147*170f4beaSVitaly Kuznetsov 	static struct option long_options[] = {
148*170f4beaSVitaly Kuznetsov 		{"help",	no_argument,	   0,  'h' },
149*170f4beaSVitaly Kuznetsov 		{"no-daemon",	no_argument,	   0,  'n' },
150*170f4beaSVitaly Kuznetsov 		{0,		0,		   0,  0   }
151*170f4beaSVitaly Kuznetsov 	};
152*170f4beaSVitaly Kuznetsov 
153*170f4beaSVitaly Kuznetsov 	while ((opt = getopt_long(argc, argv, "hn", long_options,
154*170f4beaSVitaly Kuznetsov 				  &long_index)) != -1) {
155*170f4beaSVitaly Kuznetsov 		switch (opt) {
156*170f4beaSVitaly Kuznetsov 		case 'n':
157*170f4beaSVitaly Kuznetsov 			daemonize = 0;
158*170f4beaSVitaly Kuznetsov 			break;
159*170f4beaSVitaly Kuznetsov 		case 'h':
160*170f4beaSVitaly Kuznetsov 		default:
161*170f4beaSVitaly Kuznetsov 			print_usage(argv);
162*170f4beaSVitaly Kuznetsov 			exit(EXIT_FAILURE);
163*170f4beaSVitaly Kuznetsov 		}
164*170f4beaSVitaly Kuznetsov 	}
165*170f4beaSVitaly Kuznetsov 
166*170f4beaSVitaly Kuznetsov 	if (daemonize && daemon(1, 0)) {
16701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
16801325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
16901325476SK. Y. Srinivasan 	}
17001325476SK. Y. Srinivasan 
17101325476SK. Y. Srinivasan 	openlog("HV_FCOPY", 0, LOG_USER);
17201325476SK. Y. Srinivasan 	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
17301325476SK. Y. Srinivasan 
17401325476SK. Y. Srinivasan 	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
17501325476SK. Y. Srinivasan 
17601325476SK. Y. Srinivasan 	if (fcopy_fd < 0) {
17701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
17801325476SK. Y. Srinivasan 			errno, strerror(errno));
17901325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
18001325476SK. Y. Srinivasan 	}
18101325476SK. Y. Srinivasan 
18201325476SK. Y. Srinivasan 	/*
18301325476SK. Y. Srinivasan 	 * Register with the kernel.
18401325476SK. Y. Srinivasan 	 */
18501325476SK. Y. Srinivasan 	if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
18601325476SK. Y. Srinivasan 		syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
18701325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
18801325476SK. Y. Srinivasan 	}
18901325476SK. Y. Srinivasan 
19001325476SK. Y. Srinivasan 	while (1) {
19101325476SK. Y. Srinivasan 		/*
19201325476SK. Y. Srinivasan 		 * In this loop we process fcopy messages after the
19301325476SK. Y. Srinivasan 		 * handshake is complete.
19401325476SK. Y. Srinivasan 		 */
19501325476SK. Y. Srinivasan 		len = pread(fcopy_fd, buffer, (4096 * 2), 0);
19601325476SK. Y. Srinivasan 		if (len < 0) {
19701325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pread failed: %s", strerror(errno));
19801325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
19901325476SK. Y. Srinivasan 		}
20001325476SK. Y. Srinivasan 		in_msg = (struct hv_fcopy_hdr *)buffer;
20101325476SK. Y. Srinivasan 
20201325476SK. Y. Srinivasan 		switch (in_msg->operation) {
20301325476SK. Y. Srinivasan 		case START_FILE_COPY:
20401325476SK. Y. Srinivasan 			error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
20501325476SK. Y. Srinivasan 			break;
20601325476SK. Y. Srinivasan 		case WRITE_TO_FILE:
20701325476SK. Y. Srinivasan 			error = hv_copy_data((struct hv_do_fcopy *)in_msg);
20801325476SK. Y. Srinivasan 			break;
20901325476SK. Y. Srinivasan 		case COMPLETE_FCOPY:
21001325476SK. Y. Srinivasan 			error = hv_copy_finished();
21101325476SK. Y. Srinivasan 			break;
21201325476SK. Y. Srinivasan 		case CANCEL_FCOPY:
21301325476SK. Y. Srinivasan 			error = hv_copy_cancel();
21401325476SK. Y. Srinivasan 			break;
21501325476SK. Y. Srinivasan 
21601325476SK. Y. Srinivasan 		default:
21701325476SK. Y. Srinivasan 			syslog(LOG_ERR, "Unknown operation: %d",
21801325476SK. Y. Srinivasan 				in_msg->operation);
21901325476SK. Y. Srinivasan 
22001325476SK. Y. Srinivasan 		}
22101325476SK. Y. Srinivasan 
22201325476SK. Y. Srinivasan 		if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
22301325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
22401325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
22501325476SK. Y. Srinivasan 		}
22601325476SK. Y. Srinivasan 	}
22701325476SK. Y. Srinivasan }
228