Home | History | Annotate | Line # | Download | only in puffs
t_basic.c revision 1.1
      1 /*	$NetBSD: t_basic.c,v 1.1 2010/07/06 14:44:30 pooka Exp $	*/
      2 
      3 #include <sys/types.h>
      4 #include <sys/mount.h>
      5 #include <sys/socket.h>
      6 
      7 #include <assert.h>
      8 #include <atf-c.h>
      9 #include <err.h>
     10 #include <errno.h>
     11 #include <fcntl.h>
     12 #include <puffs.h>
     13 #include <stdio.h>
     14 #include <unistd.h>
     15 #include <string.h>
     16 #include <stdlib.h>
     17 
     18 #include <rump/rump.h>
     19 #include <rump/rump_syscalls.h>
     20 
     21 #include "../../h_macros.h"
     22 
     23 struct puffs_args {
     24 	uint8_t			*us_pargs;
     25 	size_t			us_pargslen;
     26 
     27 	int			us_pflags;
     28 	int			us_servfd;
     29 	pid_t			us_childpid;
     30 };
     31 
     32 #define BUFSIZE (64*1024)
     33 
     34 struct thefds {
     35 	int rumpfd;
     36 	int servfd;
     37 };
     38 
     39 /*
     40  * Threads which shovel data between comfd and /dev/puffs.
     41  * (cannot use polling since fd's are in different namespaces)
     42  */
     43 static void *
     44 readshovel(void *arg)
     45 {
     46 	struct thefds *fds = arg;
     47 	char buf[BUFSIZE];
     48 	ssize_t n;
     49 	int error, comfd, puffsfd;
     50 
     51 	comfd = fds->servfd;
     52 	puffsfd = fds->rumpfd;
     53 
     54 	/* use static thread id */
     55 	rump_pub_lwp_alloc_and_switch(0, 0);
     56 
     57 	for (;;) {
     58 		ssize_t n, n2;
     59 
     60 		n = rump_sys_read(puffsfd, buf, BUFSIZE);
     61 		if (n <= 0) {
     62 			break;
     63 		}
     64 
     65 		while (n) {
     66 			n2 = write(comfd, buf, n);
     67 			if (n2 == -1)
     68 				err(1, "readshovel failed write: %d");
     69 			if (n2 == 0)
     70 				break;
     71 			n -= n2;
     72 		}
     73 	}
     74 
     75 	return NULL;
     76 }
     77 
     78 static void *
     79 writeshovel(void *arg)
     80 {
     81 	struct thefds *fds = arg;
     82 	struct putter_hdr *phdr;
     83 	char buf[BUFSIZE];
     84 	size_t toread;
     85 	int error, comfd, puffsfd;
     86 
     87 	/* use static thread id */
     88 	rump_pub_lwp_alloc_and_switch(0, 0);
     89 
     90 	comfd = fds->servfd;
     91 	puffsfd = fds->rumpfd;
     92 
     93 	phdr = (struct putter_hdr *)buf;
     94 
     95 	for (;;) {
     96 		off_t off;
     97 		ssize_t n;
     98 
     99 		/*
    100 		 * Need to write everything to the "kernel" in one chunk,
    101 		 * so make sure we have it here.
    102 		 */
    103 		off = 0;
    104 		toread = sizeof(struct putter_hdr);
    105 		do {
    106 			n = read(comfd, buf+off, toread);
    107 			if (n <= 0) {
    108 				break;
    109 			}
    110 			off += n;
    111 			if (off >= sizeof(struct putter_hdr))
    112 				toread = phdr->pth_framelen - off;
    113 			else
    114 				toread = off - sizeof(struct putter_hdr);
    115 		} while (toread);
    116 
    117 		n = rump_sys_write(puffsfd, buf, phdr->pth_framelen);
    118 		if (n != phdr->pth_framelen)
    119 			goto out;
    120 	}
    121 
    122  out:
    123 	return NULL;
    124 }
    125 
    126 static void
    127 rumpshovels(int rumpfd, int servfd)
    128 {
    129 	struct thefds *fds;
    130 	pthread_t pt;
    131 	int rv;
    132 
    133 	if ((rv = rump_init()) == -1)
    134 		err(1, "rump_init");
    135 
    136 	fds = malloc(sizeof(*fds));
    137 	fds->rumpfd = rumpfd;
    138 	fds->servfd = servfd;
    139 	if (pthread_create(&pt, NULL, readshovel, fds) == -1)
    140 		err(1, "read shovel");
    141 	pthread_detach(pt);
    142 	if (pthread_create(&pt, NULL, writeshovel, fds) == -1)
    143 		err(1, "write shovel");
    144 	pthread_detach(pt);
    145 }
    146 
    147 static int
    148 parseargs(int argc, char *argv[],
    149 	struct puffs_args *args, int *mntflags,
    150 	char *canon_dev, char *canon_dir)
    151 {
    152 	pid_t childpid;
    153 	pthread_t pt;
    154 	int *pflags = &args->us_pflags;
    155 	char comfd[16];
    156 	int sv[2];
    157 	size_t len;
    158 	ssize_t n;
    159 	int rv;
    160 
    161 	if (argc < 2)
    162 		errx(1, "invalid usage");
    163 
    164 	/* Create sucketpair for communication with the real file server */
    165 	if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) == -1)
    166 		err(1, "socketpair");
    167 
    168 	switch ((childpid = fork())) {
    169 	case 0:
    170 		close(sv[1]);
    171 		snprintf(comfd, sizeof(sv[0]), "%d", sv[0]);
    172 		if (setenv("PUFFS_COMFD", comfd, 1) == -1)
    173 			err(1, "setenv");
    174 
    175 		argv++;
    176 		if (execvp(argv[0], argv) == -1)
    177 			err(1, "execvp here");
    178 		/*NOTREACHED*/
    179 	case -1:
    180 		err(1, "fork");
    181 		/*NOTREACHED*/
    182 	default:
    183 		close(sv[0]);
    184 		break;
    185 	}
    186 
    187 	/* read args */
    188 	if ((n = read(sv[1], &len, sizeof(len))) != sizeof(len))
    189 		err(1, "mp 1 %zd", n);
    190 	if (len > MAXPATHLEN)
    191 		err(1, "mntpath > MAXPATHLEN");
    192 	if ((size_t)read(sv[1], canon_dir, len) != len)
    193 		err(1, "mp 2");
    194 	if (read(sv[1], &len, sizeof(len)) != sizeof(len))
    195 		err(1, "fn 1");
    196 	if (len > MAXPATHLEN)
    197 		err(1, "devpath > MAXPATHLEN");
    198 	if ((size_t)read(sv[1], canon_dev, len) != len)
    199 		err(1, "fn 2");
    200 	if (read(sv[1], mntflags, sizeof(*mntflags)) != sizeof(*mntflags))
    201 		err(1, "mntflags");
    202 	if (read(sv[1], &args->us_pargslen, sizeof(args->us_pargslen)) != sizeof(args->us_pargslen))
    203 		err(1, "puffs_args len");
    204 	args->us_pargs = malloc(args->us_pargslen);
    205 	if (args->us_pargs == NULL)
    206 		err(1, "malloc");
    207 	if (read(sv[1], args->us_pargs, args->us_pargslen) != args->us_pargslen)
    208 		err(1, "puffs_args");
    209 	if (read(sv[1], pflags, sizeof(*pflags)) != sizeof(*pflags))
    210 		err(1, "pflags");
    211 
    212 	args->us_childpid = childpid;
    213 	args->us_servfd = sv[1];
    214 
    215 	return 0;
    216 }
    217 
    218 ATF_TC(mount);
    219 ATF_TC_HEAD(mount, tc)
    220 {
    221 
    222 	atf_tc_set_md_var(tc, "descr", "puffs+dtfs un/mount test");
    223 }
    224 
    225 char *dtfsargv[] = {
    226 	"dtfs",
    227 	"BUILT_AT_RUNTIME",
    228 	"dtfs",
    229 	"/mp",
    230 	NULL
    231 };
    232 
    233 ATF_TC_BODY(mount, tc)
    234 {
    235 	char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
    236 	char dtfs_path[MAXPATHLEN];
    237 	struct puffs_args pargs;
    238 	int mntflag;
    239 	int rv;
    240 	int fd;
    241 
    242 	/* build dtfs exec path for atf */
    243 	sprintf(dtfs_path, "%s/h_dtfs/h_dtfs",
    244 	    atf_tc_get_config_var(tc, "srcdir"));
    245 	dtfsargv[1] = dtfs_path;
    246 
    247 	rump_init();
    248 
    249 	rv = parseargs(__arraycount(dtfsargv), dtfsargv,
    250 	    &pargs, &mntflag, canon_dev, canon_dir);
    251 	if (rv)
    252 		atf_tc_fail("comfd parseargs");
    253 
    254 	fd = rump_sys_open("/dev/puffs", O_RDWR);
    255 	if (fd == -1)
    256 		atf_tc_fail_errno("open puffs fd");
    257 #if 0
    258 	pargs->pa_fd = fd;
    259 #else
    260 	assert(fd == 0); /* XXX: FIXME */
    261 #endif
    262 
    263 	if (rump_sys_mkdir("/mp", 0777) == -1)
    264 		atf_tc_fail_errno("mkdir mountpoint");
    265 
    266 	if (rump_sys_mount(MOUNT_PUFFS, "/mp", 0,
    267 	    pargs.us_pargs, pargs.us_pargslen) == -1)
    268 		atf_tc_fail_errno("mount");
    269 
    270 	rumpshovels(fd, pargs.us_servfd);
    271 
    272 	if (rump_sys_unmount("/mp", 0) == -1)
    273 		atf_tc_fail_errno("unmount");
    274 }
    275 
    276 ATF_TP_ADD_TCS(tp)
    277 {
    278 	ATF_TP_ADD_TC(tp, mount);
    279 
    280 	return atf_no_error();
    281 }
    282