blob: 703ac8567f0574fe73ddacbf740645aae547f496 [file] [log] [blame]
M. Mohan Kumar17bff522011-12-14 13:58:42 +05301/*
2 * Helper for QEMU Proxy FS Driver
3 * Copyright IBM, Corp. 2011
4 *
5 * Authors:
6 * M. Mohan Kumar <mohan@in.ibm.com>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2. See
9 * the COPYING file in the top-level directory.
10 */
11#include <stdio.h>
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +053012#include <sys/socket.h>
M. Mohan Kumar17bff522011-12-14 13:58:42 +053013#include <string.h>
14#include <sys/un.h>
15#include <limits.h>
16#include <signal.h>
17#include <errno.h>
18#include <stdlib.h>
19#include <sys/resource.h>
20#include <sys/stat.h>
21#include <getopt.h>
22#include <unistd.h>
23#include <syslog.h>
24#include <sys/capability.h>
25#include <sys/fsuid.h>
26#include <stdarg.h>
27#include <stdbool.h>
M. Mohan Kumarb178adc2011-12-14 13:58:45 +053028#include <sys/vfs.h>
29#include <sys/stat.h>
M. Mohan Kumard52b09e2011-12-14 13:58:46 +053030#include <attr/xattr.h>
M. Mohan Kumar17bff522011-12-14 13:58:42 +053031#include "qemu-common.h"
32#include "virtio-9p-marshal.h"
33#include "hw/9pfs/virtio-9p-proxy.h"
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +053034#include "fsdev/virtio-9p-marshal.h"
M. Mohan Kumar17bff522011-12-14 13:58:42 +053035
36#define PROGNAME "virtfs-proxy-helper"
37
38static struct option helper_opts[] = {
39 {"fd", required_argument, NULL, 'f'},
40 {"path", required_argument, NULL, 'p'},
41 {"nodaemon", no_argument, NULL, 'n'},
42};
43
44static bool is_daemon;
45
46static void do_log(int loglevel, const char *format, ...)
47{
48 va_list ap;
49
50 va_start(ap, format);
51 if (is_daemon) {
52 vsyslog(LOG_CRIT, format, ap);
53 } else {
54 vfprintf(stderr, format, ap);
55 }
56 va_end(ap);
57}
58
59static void do_perror(const char *string)
60{
61 if (is_daemon) {
62 syslog(LOG_CRIT, "%s:%s", string, strerror(errno));
63 } else {
64 fprintf(stderr, "%s:%s\n", string, strerror(errno));
65 }
66}
67
68static int do_cap_set(cap_value_t *cap_value, int size, int reset)
69{
70 cap_t caps;
71 if (reset) {
72 /*
73 * Start with an empty set and set permitted and effective
74 */
75 caps = cap_init();
76 if (caps == NULL) {
77 do_perror("cap_init");
78 return -1;
79 }
80 if (cap_set_flag(caps, CAP_PERMITTED, size, cap_value, CAP_SET) < 0) {
81 do_perror("cap_set_flag");
82 goto error;
83 }
84 } else {
85 caps = cap_get_proc();
86 if (!caps) {
87 do_perror("cap_get_proc");
88 return -1;
89 }
90 }
91 if (cap_set_flag(caps, CAP_EFFECTIVE, size, cap_value, CAP_SET) < 0) {
92 do_perror("cap_set_flag");
93 goto error;
94 }
95 if (cap_set_proc(caps) < 0) {
96 do_perror("cap_set_proc");
97 goto error;
98 }
99 cap_free(caps);
100 return 0;
101
102error:
103 cap_free(caps);
104 return -1;
105}
106
107static int init_capabilities(void)
108{
109 /* helper needs following capbabilities only */
110 cap_value_t cap_list[] = {
111 CAP_CHOWN,
112 CAP_DAC_OVERRIDE,
113 CAP_FOWNER,
114 CAP_FSETID,
115 CAP_SETGID,
116 CAP_MKNOD,
117 CAP_SETUID,
118 };
119 return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 1);
120}
121
122static int socket_read(int sockfd, void *buff, ssize_t size)
123{
124 ssize_t retval, total = 0;
125
126 while (size) {
127 retval = read(sockfd, buff, size);
128 if (retval == 0) {
129 return -EIO;
130 }
131 if (retval < 0) {
132 if (errno == EINTR) {
133 continue;
134 }
135 return -errno;
136 }
137 size -= retval;
138 buff += retval;
139 total += retval;
140 }
141 return total;
142}
143
144static int socket_write(int sockfd, void *buff, ssize_t size)
145{
146 ssize_t retval, total = 0;
147
148 while (size) {
149 retval = write(sockfd, buff, size);
150 if (retval < 0) {
151 if (errno == EINTR) {
152 continue;
153 }
154 return -errno;
155 }
156 size -= retval;
157 buff += retval;
158 total += retval;
159 }
160 return total;
161}
162
163static int read_request(int sockfd, struct iovec *iovec, ProxyHeader *header)
164{
165 int retval;
166
167 /*
168 * read the request header.
169 */
170 iovec->iov_len = 0;
171 retval = socket_read(sockfd, iovec->iov_base, PROXY_HDR_SZ);
172 if (retval < 0) {
173 return retval;
174 }
175 iovec->iov_len = PROXY_HDR_SZ;
176 retval = proxy_unmarshal(iovec, 0, "dd", &header->type, &header->size);
177 if (retval < 0) {
178 return retval;
179 }
180 /*
181 * We can't process message.size > PROXY_MAX_IO_SZ.
182 * Treat it as fatal error
183 */
184 if (header->size > PROXY_MAX_IO_SZ) {
185 return -ENOBUFS;
186 }
187 retval = socket_read(sockfd, iovec->iov_base + PROXY_HDR_SZ, header->size);
188 if (retval < 0) {
189 return retval;
190 }
191 iovec->iov_len += header->size;
192 return 0;
193}
194
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530195static int send_fd(int sockfd, int fd)
196{
197 struct msghdr msg;
198 struct iovec iov;
199 int retval, data;
200 struct cmsghdr *cmsg;
201 union MsgControl msg_control;
202
203 iov.iov_base = &data;
204 iov.iov_len = sizeof(data);
205
206 memset(&msg, 0, sizeof(msg));
207 msg.msg_iov = &iov;
208 msg.msg_iovlen = 1;
209 /* No ancillary data on error */
210 if (fd < 0) {
211 /* fd is really negative errno if the request failed */
212 data = fd;
213 } else {
214 data = V9FS_FD_VALID;
215 msg.msg_control = &msg_control;
216 msg.msg_controllen = sizeof(msg_control);
217
218 cmsg = &msg_control.cmsg;
219 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
220 cmsg->cmsg_level = SOL_SOCKET;
221 cmsg->cmsg_type = SCM_RIGHTS;
222 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
223 }
224
225 do {
226 retval = sendmsg(sockfd, &msg, 0);
227 } while (retval < 0 && errno == EINTR);
228 if (fd >= 0) {
229 close(fd);
230 }
231 if (retval < 0) {
232 return retval;
233 }
234 return 0;
235}
236
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530237static int send_status(int sockfd, struct iovec *iovec, int status)
238{
239 ProxyHeader header;
240 int retval, msg_size;;
241
242 if (status < 0) {
243 header.type = T_ERROR;
244 } else {
245 header.type = T_SUCCESS;
246 }
247 header.size = sizeof(status);
248 /*
249 * marshal the return status. We don't check error.
250 * because we are sure we have enough space for the status
251 */
252 msg_size = proxy_marshal(iovec, 0, "ddd", header.type,
253 header.size, status);
254 retval = socket_write(sockfd, iovec->iov_base, msg_size);
255 if (retval < 0) {
256 return retval;
257 }
258 return 0;
259}
260
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530261/*
262 * from man 7 capabilities, section
263 * Effect of User ID Changes on Capabilities:
264 * 4. If the file system user ID is changed from 0 to nonzero (see setfsuid(2))
265 * then the following capabilities are cleared from the effective set:
266 * CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID,
267 * CAP_LINUX_IMMUTABLE (since Linux 2.2.30), CAP_MAC_OVERRIDE, and CAP_MKNOD
268 * (since Linux 2.2.30). If the file system UID is changed from nonzero to 0,
269 * then any of these capabilities that are enabled in the permitted set
270 * are enabled in the effective set.
271 */
272static int setfsugid(int uid, int gid)
273{
274 /*
275 * We still need DAC_OVERRIDE because we don't change
276 * supplementary group ids, and hence may be subjected DAC rules
277 */
278 cap_value_t cap_list[] = {
279 CAP_DAC_OVERRIDE,
280 };
281
282 setfsgid(gid);
283 setfsuid(uid);
284
285 if (uid != 0 || gid != 0) {
286 return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0);
287 }
288 return 0;
289}
290
291/*
M. Mohan Kumarb178adc2011-12-14 13:58:45 +0530292 * send response in two parts
293 * 1) ProxyHeader
294 * 2) Response or error status
295 * This function should be called with marshaled response
296 * send_response constructs header part and error part only.
297 * send response sends {ProxyHeader,Response} if the request was success
298 * otherwise sends {ProxyHeader,error status}
299 */
300static int send_response(int sock, struct iovec *iovec, int size)
301{
302 int retval;
303 ProxyHeader header;
304
305 /*
306 * If response size exceeds available iovec->iov_len,
307 * we return ENOBUFS
308 */
309 if (size > PROXY_MAX_IO_SZ) {
310 size = -ENOBUFS;
311 }
312
313 if (size < 0) {
314 /*
315 * In case of error we would not have got the error encoded
316 * already so encode the error here.
317 */
318 header.type = T_ERROR;
319 header.size = sizeof(size);
320 proxy_marshal(iovec, PROXY_HDR_SZ, "d", size);
321 } else {
322 header.type = T_SUCCESS;
323 header.size = size;
324 }
325 proxy_marshal(iovec, 0, "dd", header.type, header.size);
326 retval = socket_write(sock, iovec->iov_base, header.size + PROXY_HDR_SZ);
327 if (retval < 0) {
328 return retval;;
329 }
330 return 0;
331}
332
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530333static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec)
334{
335 int size = 0, offset, retval;
336 V9fsString path, name, xattr;
337
338 v9fs_string_init(&xattr);
339 v9fs_string_init(&path);
340 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "ds", &size, &path);
341 if (retval < 0) {
342 return retval;
343 }
344 offset = PROXY_HDR_SZ + retval;
345
346 if (size) {
347 xattr.data = g_malloc(size);
348 xattr.size = size;
349 }
350 switch (type) {
351 case T_LGETXATTR:
352 v9fs_string_init(&name);
353 retval = proxy_unmarshal(iovec, offset, "s", &name);
354 if (retval > 0) {
355 retval = lgetxattr(path.data, name.data, xattr.data, size);
356 if (retval < 0) {
357 retval = -errno;
358 } else {
359 xattr.size = retval;
360 }
361 }
362 v9fs_string_free(&name);
363 break;
364 case T_LLISTXATTR:
365 retval = llistxattr(path.data, xattr.data, size);
366 if (retval < 0) {
367 retval = -errno;
368 } else {
369 xattr.size = retval;
370 }
371 break;
372 }
373 if (retval < 0) {
374 goto err_out;
375 }
376
377 if (!size) {
378 proxy_marshal(out_iovec, PROXY_HDR_SZ, "d", retval);
379 retval = sizeof(retval);
380 } else {
381 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &xattr);
382 }
383err_out:
384 v9fs_string_free(&xattr);
385 v9fs_string_free(&path);
386 return retval;
387}
388
M. Mohan Kumarb178adc2011-12-14 13:58:45 +0530389static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat)
390{
391 memset(pr_stat, 0, sizeof(*pr_stat));
392 pr_stat->st_dev = stat->st_dev;
393 pr_stat->st_ino = stat->st_ino;
394 pr_stat->st_nlink = stat->st_nlink;
395 pr_stat->st_mode = stat->st_mode;
396 pr_stat->st_uid = stat->st_uid;
397 pr_stat->st_gid = stat->st_gid;
398 pr_stat->st_rdev = stat->st_rdev;
399 pr_stat->st_size = stat->st_size;
400 pr_stat->st_blksize = stat->st_blksize;
401 pr_stat->st_blocks = stat->st_blocks;
402 pr_stat->st_atim_sec = stat->st_atim.tv_sec;
403 pr_stat->st_atim_nsec = stat->st_atim.tv_nsec;
404 pr_stat->st_mtim_sec = stat->st_mtim.tv_sec;
405 pr_stat->st_mtim_nsec = stat->st_mtim.tv_nsec;
406 pr_stat->st_ctim_sec = stat->st_ctim.tv_sec;
407 pr_stat->st_ctim_nsec = stat->st_ctim.tv_nsec;
408}
409
410static void statfs_to_prstatfs(ProxyStatFS *pr_stfs, struct statfs *stfs)
411{
412 memset(pr_stfs, 0, sizeof(*pr_stfs));
413 pr_stfs->f_type = stfs->f_type;
414 pr_stfs->f_bsize = stfs->f_bsize;
415 pr_stfs->f_blocks = stfs->f_blocks;
416 pr_stfs->f_bfree = stfs->f_bfree;
417 pr_stfs->f_bavail = stfs->f_bavail;
418 pr_stfs->f_files = stfs->f_files;
419 pr_stfs->f_ffree = stfs->f_ffree;
420 pr_stfs->f_fsid[0] = stfs->f_fsid.__val[0];
421 pr_stfs->f_fsid[1] = stfs->f_fsid.__val[1];
422 pr_stfs->f_namelen = stfs->f_namelen;
423 pr_stfs->f_frsize = stfs->f_frsize;
424}
425
426/*
427 * Gets stat/statfs information and packs in out_iovec structure
428 * on success returns number of bytes packed in out_iovec struture
429 * otherwise returns -errno
430 */
431static int do_stat(int type, struct iovec *iovec, struct iovec *out_iovec)
432{
433 int retval;
434 V9fsString path;
435 ProxyStat pr_stat;
436 ProxyStatFS pr_stfs;
437 struct stat st_buf;
438 struct statfs stfs_buf;
439
440 v9fs_string_init(&path);
441 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path);
442 if (retval < 0) {
443 return retval;
444 }
445
446 switch (type) {
447 case T_LSTAT:
448 retval = lstat(path.data, &st_buf);
449 if (retval < 0) {
450 retval = -errno;
451 } else {
452 stat_to_prstat(&pr_stat, &st_buf);
453 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ,
454 "qqqdddqqqqqqqqqq", pr_stat.st_dev,
455 pr_stat.st_ino, pr_stat.st_nlink,
456 pr_stat.st_mode, pr_stat.st_uid,
457 pr_stat.st_gid, pr_stat.st_rdev,
458 pr_stat.st_size, pr_stat.st_blksize,
459 pr_stat.st_blocks,
460 pr_stat.st_atim_sec, pr_stat.st_atim_nsec,
461 pr_stat.st_mtim_sec, pr_stat.st_mtim_nsec,
462 pr_stat.st_ctim_sec, pr_stat.st_ctim_nsec);
463 }
464 break;
465 case T_STATFS:
466 retval = statfs(path.data, &stfs_buf);
467 if (retval < 0) {
468 retval = -errno;
469 } else {
470 statfs_to_prstatfs(&pr_stfs, &stfs_buf);
471 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ,
472 "qqqqqqqqqqq", pr_stfs.f_type,
473 pr_stfs.f_bsize, pr_stfs.f_blocks,
474 pr_stfs.f_bfree, pr_stfs.f_bavail,
475 pr_stfs.f_files, pr_stfs.f_ffree,
476 pr_stfs.f_fsid[0], pr_stfs.f_fsid[1],
477 pr_stfs.f_namelen, pr_stfs.f_frsize);
478 }
479 break;
480 }
481 v9fs_string_free(&path);
482 return retval;
483}
484
485static int do_readlink(struct iovec *iovec, struct iovec *out_iovec)
486{
487 char *buffer;
488 int size, retval;
489 V9fsString target, path;
490
491 v9fs_string_init(&path);
492 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &size);
493 if (retval < 0) {
494 v9fs_string_free(&path);
495 return retval;
496 }
497 buffer = g_malloc(size);
498 v9fs_string_init(&target);
499 retval = readlink(path.data, buffer, size);
500 if (retval > 0) {
501 buffer[retval] = '\0';
502 v9fs_string_sprintf(&target, "%s", buffer);
503 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &target);
504 } else {
505 retval = -errno;
506 }
507 g_free(buffer);
508 v9fs_string_free(&target);
509 v9fs_string_free(&path);
510 return retval;
511}
512
513/*
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530514 * create other filesystem objects and send 0 on success
515 * return -errno on error
516 */
517static int do_create_others(int type, struct iovec *iovec)
518{
519 dev_t rdev;
520 int retval = 0;
521 int offset = PROXY_HDR_SZ;
522 V9fsString oldpath, path;
523 int mode, uid, gid, cur_uid, cur_gid;
524
525 v9fs_string_init(&path);
526 v9fs_string_init(&oldpath);
527 cur_uid = geteuid();
528 cur_gid = getegid();
529
530 retval = proxy_unmarshal(iovec, offset, "dd", &uid, &gid);
531 if (retval < 0) {
532 return retval;
533 }
534 offset += retval;
535 retval = setfsugid(uid, gid);
536 if (retval < 0) {
537 retval = -errno;
538 goto err_out;
539 }
540 switch (type) {
541 case T_MKNOD:
542 retval = proxy_unmarshal(iovec, offset, "sdq", &path, &mode, &rdev);
543 if (retval < 0) {
544 goto err_out;
545 }
546 retval = mknod(path.data, mode, rdev);
547 break;
548 case T_MKDIR:
549 retval = proxy_unmarshal(iovec, offset, "sd", &path, &mode);
550 if (retval < 0) {
551 goto err_out;
552 }
553 retval = mkdir(path.data, mode);
554 break;
555 case T_SYMLINK:
556 retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path);
557 if (retval < 0) {
558 goto err_out;
559 }
560 retval = symlink(oldpath.data, path.data);
561 break;
562 }
563 if (retval < 0) {
564 retval = -errno;
565 }
566
567err_out:
568 v9fs_string_free(&path);
569 v9fs_string_free(&oldpath);
570 setfsugid(cur_uid, cur_gid);
571 return retval;
572}
573
574/*
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530575 * create a file and send fd on success
576 * return -errno on error
577 */
578static int do_create(struct iovec *iovec)
579{
580 int ret;
581 V9fsString path;
582 int flags, mode, uid, gid, cur_uid, cur_gid;
583
584 v9fs_string_init(&path);
585 ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sdddd",
586 &path, &flags, &mode, &uid, &gid);
587 if (ret < 0) {
588 goto unmarshal_err_out;
589 }
590 cur_uid = geteuid();
591 cur_gid = getegid();
592 ret = setfsugid(uid, gid);
593 if (ret < 0) {
594 /*
595 * On failure reset back to the
596 * old uid/gid
597 */
598 ret = -errno;
599 goto err_out;
600 }
601 ret = open(path.data, flags, mode);
602 if (ret < 0) {
603 ret = -errno;
604 }
605
606err_out:
607 setfsugid(cur_uid, cur_gid);
608unmarshal_err_out:
609 v9fs_string_free(&path);
610 return ret;
611}
612
613/*
614 * open a file and send fd on success
615 * return -errno on error
616 */
617static int do_open(struct iovec *iovec)
618{
619 int flags, ret;
620 V9fsString path;
621
622 v9fs_string_init(&path);
623 ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &flags);
624 if (ret < 0) {
625 goto err_out;
626 }
627 ret = open(path.data, flags);
628 if (ret < 0) {
629 ret = -errno;
630 }
631err_out:
632 v9fs_string_free(&path);
633 return ret;
634}
635
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530636static void usage(char *prog)
637{
638 fprintf(stderr, "usage: %s\n"
639 " -p|--path <path> 9p path to export\n"
640 " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
641 " [-n|--nodaemon] Run as a normal program\n",
642 basename(prog));
643}
644
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530645static int process_reply(int sock, int type,
646 struct iovec *out_iovec, int retval)
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530647{
648 switch (type) {
649 case T_OPEN:
650 case T_CREATE:
651 if (send_fd(sock, retval) < 0) {
652 return -1;
653 }
654 break;
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530655 case T_MKNOD:
656 case T_MKDIR:
657 case T_SYMLINK:
658 case T_LINK:
M. Mohan Kumarea75fc42011-12-14 13:58:45 +0530659 case T_CHMOD:
660 case T_CHOWN:
661 case T_TRUNCATE:
662 case T_UTIME:
663 case T_RENAME:
664 case T_REMOVE:
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530665 case T_LSETXATTR:
666 case T_LREMOVEXATTR:
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530667 if (send_status(sock, out_iovec, retval) < 0) {
668 return -1;
669 }
670 break;
M. Mohan Kumarb178adc2011-12-14 13:58:45 +0530671 case T_LSTAT:
672 case T_STATFS:
673 case T_READLINK:
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530674 case T_LGETXATTR:
675 case T_LLISTXATTR:
M. Mohan Kumarb178adc2011-12-14 13:58:45 +0530676 if (send_response(sock, out_iovec, retval) < 0) {
677 return -1;
678 }
679 break;
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530680 default:
681 return -1;
682 break;
683 }
684 return 0;
685}
686
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530687static int process_requests(int sock)
688{
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530689 int flags;
690 int size = 0;
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530691 int retval = 0;
M. Mohan Kumarea75fc42011-12-14 13:58:45 +0530692 uint64_t offset;
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530693 ProxyHeader header;
M. Mohan Kumarea75fc42011-12-14 13:58:45 +0530694 int mode, uid, gid;
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530695 V9fsString name, value;
M. Mohan Kumarea75fc42011-12-14 13:58:45 +0530696 struct timespec spec[2];
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530697 V9fsString oldpath, path;
698 struct iovec in_iovec, out_iovec;
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530699
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530700 in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
701 in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
702 out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
703 out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
704
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530705 while (1) {
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530706 /*
707 * initialize the header type, so that we send
708 * response to proper request type.
709 */
710 header.type = 0;
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530711 retval = read_request(sock, &in_iovec, &header);
712 if (retval < 0) {
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530713 goto err_out;
714 }
715
716 switch (header.type) {
717 case T_OPEN:
718 retval = do_open(&in_iovec);
719 break;
720 case T_CREATE:
721 retval = do_create(&in_iovec);
722 break;
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530723 case T_MKNOD:
724 case T_MKDIR:
725 case T_SYMLINK:
726 retval = do_create_others(header.type, &in_iovec);
727 break;
728 case T_LINK:
729 v9fs_string_init(&path);
730 v9fs_string_init(&oldpath);
731 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
732 "ss", &oldpath, &path);
733 if (retval > 0) {
734 retval = link(oldpath.data, path.data);
735 if (retval < 0) {
736 retval = -errno;
737 }
738 }
739 v9fs_string_free(&oldpath);
740 v9fs_string_free(&path);
741 break;
M. Mohan Kumarb178adc2011-12-14 13:58:45 +0530742 case T_LSTAT:
743 case T_STATFS:
744 retval = do_stat(header.type, &in_iovec, &out_iovec);
745 break;
746 case T_READLINK:
747 retval = do_readlink(&in_iovec, &out_iovec);
748 break;
M. Mohan Kumarea75fc42011-12-14 13:58:45 +0530749 case T_CHMOD:
750 v9fs_string_init(&path);
751 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
752 "sd", &path, &mode);
753 if (retval > 0) {
754 retval = chmod(path.data, mode);
755 if (retval < 0) {
756 retval = -errno;
757 }
758 }
759 v9fs_string_free(&path);
760 break;
761 case T_CHOWN:
762 v9fs_string_init(&path);
763 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sdd", &path,
764 &uid, &gid);
765 if (retval > 0) {
766 retval = lchown(path.data, uid, gid);
767 if (retval < 0) {
768 retval = -errno;
769 }
770 }
771 v9fs_string_free(&path);
772 break;
773 case T_TRUNCATE:
774 v9fs_string_init(&path);
775 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sq",
776 &path, &offset);
777 if (retval > 0) {
778 retval = truncate(path.data, offset);
779 if (retval < 0) {
780 retval = -errno;
781 }
782 }
783 v9fs_string_free(&path);
784 break;
785 case T_UTIME:
786 v9fs_string_init(&path);
787 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sqqqq", &path,
788 &spec[0].tv_sec, &spec[0].tv_nsec,
789 &spec[1].tv_sec, &spec[1].tv_nsec);
790 if (retval > 0) {
791 retval = qemu_utimens(path.data, spec);
792 if (retval < 0) {
793 retval = -errno;
794 }
795 }
796 v9fs_string_free(&path);
797 break;
798 case T_RENAME:
799 v9fs_string_init(&path);
800 v9fs_string_init(&oldpath);
801 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
802 "ss", &oldpath, &path);
803 if (retval > 0) {
804 retval = rename(oldpath.data, path.data);
805 if (retval < 0) {
806 retval = -errno;
807 }
808 }
809 v9fs_string_free(&oldpath);
810 v9fs_string_free(&path);
811 break;
812 case T_REMOVE:
813 v9fs_string_init(&path);
814 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "s", &path);
815 if (retval > 0) {
816 retval = remove(path.data);
817 if (retval < 0) {
818 retval = -errno;
819 }
820 }
821 v9fs_string_free(&path);
822 break;
M. Mohan Kumard52b09e2011-12-14 13:58:46 +0530823 case T_LGETXATTR:
824 case T_LLISTXATTR:
825 retval = do_getxattr(header.type, &in_iovec, &out_iovec);
826 break;
827 case T_LSETXATTR:
828 v9fs_string_init(&path);
829 v9fs_string_init(&name);
830 v9fs_string_init(&value);
831 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sssdd", &path,
832 &name, &value, &size, &flags);
833 if (retval > 0) {
834 retval = lsetxattr(path.data,
835 name.data, value.data, size, flags);
836 if (retval < 0) {
837 retval = -errno;
838 }
839 }
840 v9fs_string_free(&path);
841 v9fs_string_free(&name);
842 v9fs_string_free(&value);
843 break;
844 case T_LREMOVEXATTR:
845 v9fs_string_init(&path);
846 v9fs_string_init(&name);
847 retval = proxy_unmarshal(&in_iovec,
848 PROXY_HDR_SZ, "ss", &path, &name);
849 if (retval > 0) {
850 retval = lremovexattr(path.data, name.data);
851 if (retval < 0) {
852 retval = -errno;
853 }
854 }
855 v9fs_string_free(&path);
856 v9fs_string_free(&name);
857 break;
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530858 default:
859 goto err_out;
860 break;
861 }
862
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530863 if (process_reply(sock, header.type, &out_iovec, retval) < 0) {
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530864 goto err_out;
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530865 }
866 }
M. Mohan Kumardaf0b9a2011-12-14 13:58:44 +0530867err_out:
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530868 g_free(in_iovec.iov_base);
M. Mohan Kumar39f8c322011-12-14 13:58:45 +0530869 g_free(out_iovec.iov_base);
M. Mohan Kumar17bff522011-12-14 13:58:42 +0530870 return -1;
871}
872
873int main(int argc, char **argv)
874{
875 int sock;
876 char *rpath = NULL;
877 struct stat stbuf;
878 int c, option_index;
879
880 is_daemon = true;
881 sock = -1;
882 while (1) {
883 option_index = 0;
884 c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
885 &option_index);
886 if (c == -1) {
887 break;
888 }
889 switch (c) {
890 case 'p':
891 rpath = strdup(optarg);
892 break;
893 case 'n':
894 is_daemon = false;
895 break;
896 case 'f':
897 sock = atoi(optarg);
898 break;
899 case '?':
900 case 'h':
901 default:
902 usage(argv[0]);
903 exit(EXIT_FAILURE);
904 }
905 }
906
907 /* Parameter validation */
908 if (sock == -1 || rpath == NULL) {
909 fprintf(stderr, "socket descriptor or path not specified\n");
910 usage(argv[0]);
911 exit(EXIT_FAILURE);
912 }
913
914 if (lstat(rpath, &stbuf) < 0) {
915 fprintf(stderr, "invalid path \"%s\" specified, %s\n",
916 rpath, strerror(errno));
917 exit(EXIT_FAILURE);
918 }
919
920 if (!S_ISDIR(stbuf.st_mode)) {
921 fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
922 exit(EXIT_FAILURE);
923 }
924
925 if (is_daemon) {
926 if (daemon(0, 0) < 0) {
927 fprintf(stderr, "daemon call failed\n");
928 exit(EXIT_FAILURE);
929 }
930 openlog(PROGNAME, LOG_PID, LOG_DAEMON);
931 }
932
933 do_log(LOG_INFO, "Started\n");
934
935 if (chdir("/") < 0) {
936 do_perror("chdir");
937 goto error;
938 }
939 if (chroot(rpath) < 0) {
940 do_perror("chroot");
941 goto error;
942 }
943 umask(0);
944
945 if (init_capabilities() < 0) {
946 goto error;
947 }
948
949 process_requests(sock);
950error:
951 do_log(LOG_INFO, "Done\n");
952 closelog();
953 return 0;
954}