Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
[deliverable/linux.git] / tools / hv / hv_fcopy_daemon.c
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
37 static int target_fd;
38 static char target_fname[W_MAX_PATH];
39
40 static int hv_start_fcopy(struct hv_start_fcopy *smsg)
41 {
42 int error = HV_E_FAIL;
43 char *q, *p;
44
45 /*
46 * If possile append a path seperator to the path.
47 */
48 if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
49 strcat((char *)smsg->path_name, "/");
50
51 p = (char *)smsg->path_name;
52 snprintf(target_fname, sizeof(target_fname), "%s/%s",
53 (char *)smsg->path_name, smsg->file_name);
54
55 syslog(LOG_INFO, "Target file name: %s", target_fname);
56 /*
57 * Check to see if the path is already in place; if not,
58 * create if required.
59 */
60 while ((q = strchr(p, '/')) != NULL) {
61 if (q == p) {
62 p++;
63 continue;
64 }
65 *q = '\0';
66 if (access((char *)smsg->path_name, F_OK)) {
67 if (smsg->copy_flags & CREATE_PATH) {
68 if (mkdir((char *)smsg->path_name, 0755)) {
69 syslog(LOG_ERR, "Failed to create %s",
70 (char *)smsg->path_name);
71 goto done;
72 }
73 } else {
74 syslog(LOG_ERR, "Invalid path: %s",
75 (char *)smsg->path_name);
76 goto done;
77 }
78 }
79 p = q + 1;
80 *q = '/';
81 }
82
83 if (!access(target_fname, F_OK)) {
84 syslog(LOG_INFO, "File: %s exists", target_fname);
85 if (!smsg->copy_flags & OVER_WRITE)
86 goto done;
87 }
88
89 target_fd = open(target_fname, O_RDWR | O_CREAT | 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;
96 done:
97 return error;
98 }
99
100 static int hv_copy_data(struct hv_do_fcopy *cpmsg)
101 {
102 ssize_t bytes_written;
103
104 bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
105 cpmsg->offset);
106
107 if (bytes_written != cpmsg->size)
108 return HV_E_FAIL;
109
110 return 0;
111 }
112
113 static int hv_copy_finished(void)
114 {
115 close(target_fd);
116 return 0;
117 }
118 static int hv_copy_cancel(void)
119 {
120 close(target_fd);
121 unlink(target_fname);
122 return 0;
123
124 }
125
126 int main(void)
127 {
128 int fd, fcopy_fd, len;
129 int error;
130 int version = FCOPY_CURRENT_VERSION;
131 char *buffer[4096 * 2];
132 struct hv_fcopy_hdr *in_msg;
133
134 if (daemon(1, 0)) {
135 syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
136 exit(EXIT_FAILURE);
137 }
138
139 openlog("HV_FCOPY", 0, LOG_USER);
140 syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
141
142 fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
143
144 if (fcopy_fd < 0) {
145 syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
146 errno, strerror(errno));
147 exit(EXIT_FAILURE);
148 }
149
150 /*
151 * Register with the kernel.
152 */
153 if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
154 syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
155 exit(EXIT_FAILURE);
156 }
157
158 while (1) {
159 /*
160 * In this loop we process fcopy messages after the
161 * handshake is complete.
162 */
163 len = pread(fcopy_fd, buffer, (4096 * 2), 0);
164 if (len < 0) {
165 syslog(LOG_ERR, "pread failed: %s", strerror(errno));
166 exit(EXIT_FAILURE);
167 }
168 in_msg = (struct hv_fcopy_hdr *)buffer;
169
170 switch (in_msg->operation) {
171 case START_FILE_COPY:
172 error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
173 break;
174 case WRITE_TO_FILE:
175 error = hv_copy_data((struct hv_do_fcopy *)in_msg);
176 break;
177 case COMPLETE_FCOPY:
178 error = hv_copy_finished();
179 break;
180 case CANCEL_FCOPY:
181 error = hv_copy_cancel();
182 break;
183
184 default:
185 syslog(LOG_ERR, "Unknown operation: %d",
186 in_msg->operation);
187
188 }
189
190 if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
191 syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
192 exit(EXIT_FAILURE);
193 }
194 }
195 }
This page took 0.038848 seconds and 5 git commands to generate.