xref: /openbmc/linux/tools/hv/hv_fcopy_daemon.c (revision 314672a2c2780212fb770bb02d2fffaa1019823f)
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>
3601325476SK. Y. Srinivasan 
3701325476SK. Y. Srinivasan static int target_fd;
3801325476SK. Y. Srinivasan static char target_fname[W_MAX_PATH];
3901325476SK. Y. Srinivasan 
4001325476SK. Y. Srinivasan static int hv_start_fcopy(struct hv_start_fcopy *smsg)
4101325476SK. Y. Srinivasan {
4201325476SK. Y. Srinivasan 	int error = HV_E_FAIL;
4301325476SK. Y. Srinivasan 	char *q, *p;
4401325476SK. Y. Srinivasan 
4501325476SK. Y. Srinivasan 	/*
4601325476SK. Y. Srinivasan 	 * If possile append a path seperator to the path.
4701325476SK. Y. Srinivasan 	 */
4801325476SK. Y. Srinivasan 	if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
4901325476SK. Y. Srinivasan 		strcat((char *)smsg->path_name, "/");
5001325476SK. Y. Srinivasan 
5101325476SK. Y. Srinivasan 	p = (char *)smsg->path_name;
5201325476SK. Y. Srinivasan 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
5301325476SK. Y. Srinivasan 		(char *)smsg->path_name, smsg->file_name);
5401325476SK. Y. Srinivasan 
5501325476SK. Y. Srinivasan 	syslog(LOG_INFO, "Target file name: %s", target_fname);
5601325476SK. Y. Srinivasan 	/*
5701325476SK. Y. Srinivasan 	 * Check to see if the path is already in place; if not,
5801325476SK. Y. Srinivasan 	 * create if required.
5901325476SK. Y. Srinivasan 	 */
6001325476SK. Y. Srinivasan 	while ((q = strchr(p, '/')) != NULL) {
6101325476SK. Y. Srinivasan 		if (q == p) {
6201325476SK. Y. Srinivasan 			p++;
6301325476SK. Y. Srinivasan 			continue;
6401325476SK. Y. Srinivasan 		}
6501325476SK. Y. Srinivasan 		*q = '\0';
6601325476SK. Y. Srinivasan 		if (access((char *)smsg->path_name, F_OK)) {
6701325476SK. Y. Srinivasan 			if (smsg->copy_flags & CREATE_PATH) {
6801325476SK. Y. Srinivasan 				if (mkdir((char *)smsg->path_name, 0755)) {
6901325476SK. Y. Srinivasan 					syslog(LOG_ERR, "Failed to create %s",
7001325476SK. Y. Srinivasan 						(char *)smsg->path_name);
7101325476SK. Y. Srinivasan 					goto done;
7201325476SK. Y. Srinivasan 				}
7301325476SK. Y. Srinivasan 			} else {
7401325476SK. Y. Srinivasan 				syslog(LOG_ERR, "Invalid path: %s",
7501325476SK. Y. Srinivasan 					(char *)smsg->path_name);
7601325476SK. Y. Srinivasan 				goto done;
7701325476SK. Y. Srinivasan 			}
7801325476SK. Y. Srinivasan 		}
7901325476SK. Y. Srinivasan 		p = q + 1;
8001325476SK. Y. Srinivasan 		*q = '/';
8101325476SK. Y. Srinivasan 	}
8201325476SK. Y. Srinivasan 
8301325476SK. Y. Srinivasan 	if (!access(target_fname, F_OK)) {
8401325476SK. Y. Srinivasan 		syslog(LOG_INFO, "File: %s exists", target_fname);
85*314672a2SK. Y. Srinivasan 		if (!(smsg->copy_flags & OVER_WRITE)) {
86*314672a2SK. Y. Srinivasan 			error = HV_ERROR_ALREADY_EXISTS;
8701325476SK. Y. Srinivasan 			goto done;
8801325476SK. Y. Srinivasan 		}
89*314672a2SK. Y. Srinivasan 	}
9001325476SK. Y. Srinivasan 
9101325476SK. Y. Srinivasan 	target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
9201325476SK. Y. Srinivasan 	if (target_fd == -1) {
9301325476SK. Y. Srinivasan 		syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
9401325476SK. Y. Srinivasan 		goto done;
9501325476SK. Y. Srinivasan 	}
9601325476SK. Y. Srinivasan 
9701325476SK. Y. Srinivasan 	error = 0;
9801325476SK. Y. Srinivasan done:
9901325476SK. Y. Srinivasan 	return error;
10001325476SK. Y. Srinivasan }
10101325476SK. Y. Srinivasan 
10201325476SK. Y. Srinivasan static int hv_copy_data(struct hv_do_fcopy *cpmsg)
10301325476SK. Y. Srinivasan {
10401325476SK. Y. Srinivasan 	ssize_t bytes_written;
10501325476SK. Y. Srinivasan 
10601325476SK. Y. Srinivasan 	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
10701325476SK. Y. Srinivasan 				cpmsg->offset);
10801325476SK. Y. Srinivasan 
10901325476SK. Y. Srinivasan 	if (bytes_written != cpmsg->size)
11001325476SK. Y. Srinivasan 		return HV_E_FAIL;
11101325476SK. Y. Srinivasan 
11201325476SK. Y. Srinivasan 	return 0;
11301325476SK. Y. Srinivasan }
11401325476SK. Y. Srinivasan 
11501325476SK. Y. Srinivasan static int hv_copy_finished(void)
11601325476SK. Y. Srinivasan {
11701325476SK. Y. Srinivasan 	close(target_fd);
11801325476SK. Y. Srinivasan 	return 0;
11901325476SK. Y. Srinivasan }
12001325476SK. Y. Srinivasan static int hv_copy_cancel(void)
12101325476SK. Y. Srinivasan {
12201325476SK. Y. Srinivasan 	close(target_fd);
12301325476SK. Y. Srinivasan 	unlink(target_fname);
12401325476SK. Y. Srinivasan 	return 0;
12501325476SK. Y. Srinivasan 
12601325476SK. Y. Srinivasan }
12701325476SK. Y. Srinivasan 
12801325476SK. Y. Srinivasan int main(void)
12901325476SK. Y. Srinivasan {
13001325476SK. Y. Srinivasan 	int fd, fcopy_fd, len;
13101325476SK. Y. Srinivasan 	int error;
13201325476SK. Y. Srinivasan 	int version = FCOPY_CURRENT_VERSION;
13301325476SK. Y. Srinivasan 	char *buffer[4096 * 2];
13401325476SK. Y. Srinivasan 	struct hv_fcopy_hdr *in_msg;
13501325476SK. Y. Srinivasan 
13601325476SK. Y. Srinivasan 	if (daemon(1, 0)) {
13701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
13801325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
13901325476SK. Y. Srinivasan 	}
14001325476SK. Y. Srinivasan 
14101325476SK. Y. Srinivasan 	openlog("HV_FCOPY", 0, LOG_USER);
14201325476SK. Y. Srinivasan 	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
14301325476SK. Y. Srinivasan 
14401325476SK. Y. Srinivasan 	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
14501325476SK. Y. Srinivasan 
14601325476SK. Y. Srinivasan 	if (fcopy_fd < 0) {
14701325476SK. Y. Srinivasan 		syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
14801325476SK. Y. Srinivasan 			errno, strerror(errno));
14901325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
15001325476SK. Y. Srinivasan 	}
15101325476SK. Y. Srinivasan 
15201325476SK. Y. Srinivasan 	/*
15301325476SK. Y. Srinivasan 	 * Register with the kernel.
15401325476SK. Y. Srinivasan 	 */
15501325476SK. Y. Srinivasan 	if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
15601325476SK. Y. Srinivasan 		syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
15701325476SK. Y. Srinivasan 		exit(EXIT_FAILURE);
15801325476SK. Y. Srinivasan 	}
15901325476SK. Y. Srinivasan 
16001325476SK. Y. Srinivasan 	while (1) {
16101325476SK. Y. Srinivasan 		/*
16201325476SK. Y. Srinivasan 		 * In this loop we process fcopy messages after the
16301325476SK. Y. Srinivasan 		 * handshake is complete.
16401325476SK. Y. Srinivasan 		 */
16501325476SK. Y. Srinivasan 		len = pread(fcopy_fd, buffer, (4096 * 2), 0);
16601325476SK. Y. Srinivasan 		if (len < 0) {
16701325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pread failed: %s", strerror(errno));
16801325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
16901325476SK. Y. Srinivasan 		}
17001325476SK. Y. Srinivasan 		in_msg = (struct hv_fcopy_hdr *)buffer;
17101325476SK. Y. Srinivasan 
17201325476SK. Y. Srinivasan 		switch (in_msg->operation) {
17301325476SK. Y. Srinivasan 		case START_FILE_COPY:
17401325476SK. Y. Srinivasan 			error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
17501325476SK. Y. Srinivasan 			break;
17601325476SK. Y. Srinivasan 		case WRITE_TO_FILE:
17701325476SK. Y. Srinivasan 			error = hv_copy_data((struct hv_do_fcopy *)in_msg);
17801325476SK. Y. Srinivasan 			break;
17901325476SK. Y. Srinivasan 		case COMPLETE_FCOPY:
18001325476SK. Y. Srinivasan 			error = hv_copy_finished();
18101325476SK. Y. Srinivasan 			break;
18201325476SK. Y. Srinivasan 		case CANCEL_FCOPY:
18301325476SK. Y. Srinivasan 			error = hv_copy_cancel();
18401325476SK. Y. Srinivasan 			break;
18501325476SK. Y. Srinivasan 
18601325476SK. Y. Srinivasan 		default:
18701325476SK. Y. Srinivasan 			syslog(LOG_ERR, "Unknown operation: %d",
18801325476SK. Y. Srinivasan 				in_msg->operation);
18901325476SK. Y. Srinivasan 
19001325476SK. Y. Srinivasan 		}
19101325476SK. Y. Srinivasan 
19201325476SK. Y. Srinivasan 		if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
19301325476SK. Y. Srinivasan 			syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
19401325476SK. Y. Srinivasan 			exit(EXIT_FAILURE);
19501325476SK. Y. Srinivasan 		}
19601325476SK. Y. Srinivasan 	}
19701325476SK. Y. Srinivasan }
198