Home | History | Annotate | Line # | Download | only in umserv
umserv.c revision 1.1
      1 /*	$NetBSD: umserv.c,v 1.1 2009/12/22 18:36:02 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * This is a [quick, simple & dirty] userspace sd@umass server.
     30  * We probe USB devices using rump and attach them to the host kernel
     31  * using pud(4).  The resulting block devices can be e.g. read
     32  * and/or mounted.
     33  *
     34  * Since there is no devfs support in NetBSD, we create crudo & cotto
     35  * device nodes in the current directory.  Operating on these in the
     36  * host OS will direct operations to this userspace server, e.g.:
     37  *   golem> disklabel ./rumpsd0d
     38  *   golem> mount_msdos ./rumpsd0e /mnt
     39  * will cause file system access to /mnt be backed by the umass server
     40  * in userspace.  Due to the relatively experimental nature of this
     41  * server, rump file servers are recommended for mounting experiments.
     42  */
     43 
     44 #include <sys/types.h>
     45 #include <sys/syslimits.h>
     46 
     47 #include <dev/pud/pud_msgif.h>
     48 
     49 #include <rump/rump.h>
     50 
     51 #include <assert.h>
     52 #include <err.h>
     53 #include <errno.h>
     54 #include <fcntl.h>
     55 #include <paths.h>
     56 #include <stdio.h>
     57 #include <stdlib.h>
     58 #include <string.h>
     59 #include <unistd.h>
     60 
     61 /*
     62  * No devfs?  No problem.  We just hack a bit & wait for the dust to settle.
     63  */
     64 #define NODEBASE "rumpsd0"
     65 #define MYMAJOR 411
     66 static int
     67 makenodes(void)
     68 {
     69 	char path[PATH_MAX];
     70 	struct stat sb;
     71 	int i, j, rv;
     72 
     73 	for (i = 0; i < 2; i++) {
     74 		int minnum = 0;
     75 
     76 		for (j = 0; j < 8; j++, minnum++) {
     77 			sprintf(path, "%s%s%c",
     78 			    i == 0 ? "" : "r", NODEBASE, minnum + 'a');
     79 			if (stat(path, &sb) == 0)
     80 				continue;
     81 			rv = mknod(path, (i == 0 ? S_IFBLK : S_IFCHR) | 0666,
     82 			    makedev(MYMAJOR, minnum));
     83 			if (rv != 0 && !(rv == -1 && errno == EEXIST))
     84 				return rv;
     85 		}
     86 	}
     87 
     88 	return 0;
     89 }
     90 
     91 int
     92 main(int argc, char *argv[])
     93 {
     94 	char path[PATH_MAX];
     95 	struct pud_conf_reg pcr;
     96 	struct pud_req *pdr;
     97 	struct vnode *devvps[8], *devvp;
     98 	kauth_cred_t rootcred;
     99 	ssize_t n;
    100 	int fd, rv, i;
    101 
    102 	if (makenodes() == -1)
    103 		err(1, "makenodes");
    104 
    105 	fd = open(_PATH_PUD, O_RDWR);
    106 	if (fd == -1)
    107 		err(1, "open");
    108 
    109 #define PDRSIZE (64*1024+1024)
    110 	pdr = malloc(PDRSIZE);
    111 	if (pdr == NULL)
    112 		err(1, "malloc");
    113 
    114 	memset(&pcr, 0, sizeof(pcr));
    115 	pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
    116 	pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION;
    117 	pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
    118 	pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
    119 
    120 	pcr.pm_regdev = makedev(MYMAJOR, 0);
    121 	pcr.pm_flags = PUD_CONFFLAG_BDEV;
    122 	strlcpy(pcr.pm_devname, "youmass", sizeof(pcr.pm_devname));
    123 
    124 	n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
    125 	if (n == -1)
    126 		err(1, "configure"); /* XXX: doubles as protocol error */
    127 
    128 	rump_boot_sethowto(RUMP_AB_VERBOSE);
    129 	rump_init();
    130 
    131 	/*
    132 	 * We use the raw devices.  This avoids undesired block caching
    133 	 * in read/write.  It's also simpler.  It's even mostly correct.
    134 	 *
    135 	 * As is probably obvious by now, we execute ops through specfs.
    136 	 * Why?  Can't say it wasn't because specfs-via-vnodes was
    137 	 * already supported by rump.  But, that's mostly how the
    138 	 * kernel does it (cf. mounting file system etc).
    139 	 */
    140 	for (i = 0; i < 8; i++) {
    141 		sprintf(path, "/dev/rsd0%c", 'a' + i);
    142 		if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, path,
    143 		    NULL, &devvps[i], NULL)) != 0)
    144 			errx(1, "raw device lookup failed %d", rv);
    145 	}
    146 
    147 	rootcred = rump_pub_cred_create(0, 0, 0, NULL);
    148 
    149 	/* process requests ad infinitum */
    150 	for (;;) {
    151 		struct pud_creq_open *pr_open;
    152 		struct pud_creq_close *pr_close;
    153 		struct pud_req_readwrite *pr_rw;
    154 		struct pud_req_ioctl *pr_ioctl;
    155 		struct uio *uio;
    156 		size_t reslen;
    157 		int minordev;
    158 
    159 		n = read(fd, pdr, PDRSIZE);
    160 		if (n == -1)
    161 			err(1, "read");
    162 
    163 		minordev = minor(pdr->pdr_dev);
    164 		if (minordev < 0 || minordev >= 8) {
    165 			rv = ENXIO;
    166 			goto sendresponse;
    167 		}
    168 		devvp = devvps[minordev];
    169 
    170 		switch (pdr->pdr_reqtype) {
    171 		case PUD_BDEV_OPEN:
    172 			pr_open = (void *)pdr;
    173 			RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
    174 			rv = RUMP_VOP_OPEN(devvp, pr_open->pm_fmt, rootcred);
    175 			RUMP_VOP_UNLOCK(devvp, 0);
    176 			break;
    177 
    178 		case PUD_BDEV_CLOSE:
    179 			pr_close = (void *)pdr;
    180 			RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
    181 			rv = RUMP_VOP_CLOSE(devvp, pr_close->pm_fmt, rootcred);
    182 			RUMP_VOP_UNLOCK(devvp, 0);
    183 			break;
    184 
    185 		case PUD_BDEV_IOCTL:
    186 			pr_ioctl = (void *)pdr;
    187 			rv = RUMP_VOP_IOCTL(devvp, pr_ioctl->pm_iocmd,
    188 			    pr_ioctl->pm_data, pr_ioctl->pm_flag, rootcred);
    189 			break;
    190 
    191 		case PUD_BDEV_STRATREAD:
    192 			pr_rw = (void *)pdr;
    193 			assert(pr_rw->pm_resid <= 64*1024);
    194 			uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
    195 			    pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_READ);
    196 			RUMP_VOP_LOCK(devvp, RUMP_LK_SHARED);
    197 			rv = RUMP_VOP_READ(devvp, uio, 0, rootcred);
    198 			RUMP_VOP_UNLOCK(devvp, 0);
    199 			reslen = rump_pub_uio_free(uio);
    200 			pdr->pdr_pth.pth_framelen -= reslen;
    201 			pr_rw->pm_resid = reslen;
    202 			break;
    203 
    204 		case PUD_BDEV_STRATWRITE:
    205 			pr_rw = (void *)pdr;
    206 			uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
    207 			    pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_WRITE);
    208 			RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
    209 			rv = RUMP_VOP_WRITE(devvp, uio, 0, rootcred);
    210 			RUMP_VOP_UNLOCK(devvp, 0);
    211 			reslen = rump_pub_uio_free(uio);
    212 			pr_rw->pm_resid = reslen;
    213 			pdr->pdr_pth.pth_framelen=sizeof(struct pud_creq_write);
    214 			rv = 0;
    215 			break;
    216 
    217 		}
    218 
    219  sendresponse:
    220 		pdr->pdr_rv = rv;
    221 		n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
    222 		assert(n == (ssize_t)pdr->pdr_pth.pth_framelen);
    223 	}
    224 }
    225