Home | History | Annotate | Line # | Download | only in mount_psshfs
psshfs.c revision 1.66
      1  1.66  christos /*	$NetBSD: psshfs.c,v 1.66 2012/11/04 22:46:08 christos Exp $	*/
      2   1.1     pooka 
      3   1.1     pooka /*
      4  1.52     pooka  * Copyright (c) 2006-2009  Antti Kantee.  All Rights Reserved.
      5   1.1     pooka  *
      6   1.1     pooka  * Redistribution and use in source and binary forms, with or without
      7   1.1     pooka  * modification, are permitted provided that the following conditions
      8   1.1     pooka  * are met:
      9   1.1     pooka  * 1. Redistributions of source code must retain the above copyright
     10   1.1     pooka  *    notice, this list of conditions and the following disclaimer.
     11   1.1     pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1     pooka  *    notice, this list of conditions and the following disclaimer in the
     13   1.1     pooka  *    documentation and/or other materials provided with the distribution.
     14   1.1     pooka  *
     15   1.1     pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16   1.1     pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17   1.1     pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18   1.1     pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19   1.1     pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20   1.1     pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21   1.1     pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22   1.1     pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23   1.1     pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24   1.1     pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25   1.1     pooka  * SUCH DAMAGE.
     26   1.1     pooka  */
     27   1.1     pooka 
     28   1.1     pooka /*
     29   1.1     pooka  * psshfs: puffs sshfs
     30   1.1     pooka  *
     31   1.1     pooka  * psshfs implements sshfs functionality on top of puffs making it
     32   1.1     pooka  * possible to mount a filesystme through the sftp service.
     33   1.1     pooka  *
     34   1.1     pooka  * psshfs can execute multiple operations in "parallel" by using the
     35   1.1     pooka  * puffs_cc framework for continuations.
     36   1.1     pooka  *
     37   1.1     pooka  * Concurrency control is handled currently by vnode locking (this
     38   1.1     pooka  * will change in the future).  Context switch locations are easy to
     39  1.17     pooka  * find by grepping for puffs_framebuf_enqueue_cc().
     40   1.1     pooka  */
     41   1.1     pooka 
     42   1.1     pooka #include <sys/cdefs.h>
     43   1.1     pooka #ifndef lint
     44  1.66  christos __RCSID("$NetBSD: psshfs.c,v 1.66 2012/11/04 22:46:08 christos Exp $");
     45   1.1     pooka #endif /* !lint */
     46   1.1     pooka 
     47   1.1     pooka #include <sys/types.h>
     48  1.54     pooka #include <sys/wait.h>
     49  1.66  christos #include <sys/socket.h>
     50   1.1     pooka 
     51  1.66  christos #include <stdio.h>
     52   1.1     pooka #include <assert.h>
     53   1.1     pooka #include <err.h>
     54   1.1     pooka #include <errno.h>
     55   1.2     pooka #include <mntopts.h>
     56  1.28     pooka #include <paths.h>
     57   1.1     pooka #include <poll.h>
     58   1.1     pooka #include <puffs.h>
     59   1.1     pooka #include <signal.h>
     60   1.1     pooka #include <stdlib.h>
     61   1.1     pooka #include <util.h>
     62   1.1     pooka #include <unistd.h>
     63   1.1     pooka 
     64   1.1     pooka #include "psshfs.h"
     65   1.1     pooka 
     66  1.51     pooka static int	pssh_connect(struct puffs_usermount *, int);
     67  1.42     pooka static void	psshfs_loopfn(struct puffs_usermount *);
     68  1.65     joerg __dead static void	usage(void);
     69  1.64  jakllsch static char *	cleanhostname(char *);
     70  1.64  jakllsch static char *	colon(char *);
     71  1.55     pooka static void	add_ssharg(char ***, int *, const char *);
     72  1.49     pooka static void	psshfs_notify(struct puffs_usermount *, int, int);
     73   1.1     pooka 
     74   1.1     pooka #define SSH_PATH "/usr/bin/ssh"
     75   1.1     pooka 
     76  1.36     pooka unsigned int max_reads;
     77  1.42     pooka static int sighup;
     78  1.36     pooka 
     79  1.64  jakllsch static char *
     80  1.64  jakllsch cleanhostname(char *host)
     81  1.64  jakllsch {
     82  1.64  jakllsch 	if (*host == '[' && host[strlen(host) - 1] == ']') {
     83  1.64  jakllsch 		host[strlen(host) - 1] = '\0';
     84  1.64  jakllsch 		return (host + 1);
     85  1.64  jakllsch 	} else
     86  1.64  jakllsch 		return host;
     87  1.64  jakllsch }
     88  1.64  jakllsch 
     89  1.64  jakllsch static char *
     90  1.64  jakllsch colon(char *cp)
     91  1.64  jakllsch {
     92  1.64  jakllsch 	int flag = 0;
     93  1.64  jakllsch 
     94  1.64  jakllsch 	if (*cp == '[')
     95  1.64  jakllsch 		flag = 1;
     96  1.64  jakllsch 
     97  1.64  jakllsch 	for (; *cp; ++cp) {
     98  1.64  jakllsch 		if (*cp == '@' && *(cp+1) == '[')
     99  1.64  jakllsch 			flag = 1;
    100  1.64  jakllsch 		if (*cp == ']' && *(cp+1) == ':' && flag)
    101  1.64  jakllsch 			return (cp+1);
    102  1.64  jakllsch 		if (*cp == ':' && !flag)
    103  1.64  jakllsch 			return (cp);
    104  1.64  jakllsch 		if (*cp == '/')
    105  1.64  jakllsch 			return NULL;
    106  1.64  jakllsch 	}
    107  1.64  jakllsch 	return NULL;
    108  1.64  jakllsch }
    109  1.64  jakllsch 
    110   1.2     pooka static void
    111  1.55     pooka add_ssharg(char ***sshargs, int *nargs, const char *arg)
    112  1.21       tnn {
    113  1.21       tnn 
    114  1.21       tnn 	*sshargs = realloc(*sshargs, (*nargs + 2) * sizeof(char*));
    115  1.21       tnn 	if (!*sshargs)
    116  1.21       tnn 		err(1, "realloc");
    117  1.55     pooka 	(*sshargs)[(*nargs)++] = estrdup(arg);
    118  1.21       tnn 	(*sshargs)[*nargs] = NULL;
    119  1.21       tnn }
    120  1.21       tnn 
    121  1.21       tnn static void
    122  1.65     joerg usage(void)
    123   1.2     pooka {
    124   1.2     pooka 
    125  1.23     pooka 	fprintf(stderr, "usage: %s "
    126  1.51     pooka 	    "[-ceprst] [-F configfile] [-O sshopt=value] [-o opts] "
    127  1.47      jmmv 	    "user@host:path mountpath\n",
    128   1.4     pooka 	    getprogname());
    129  1.23     pooka 	exit(1);
    130   1.2     pooka }
    131   1.2     pooka 
    132  1.42     pooka static void
    133  1.42     pooka takehup(int sig)
    134  1.42     pooka {
    135  1.42     pooka 
    136  1.42     pooka 	sighup = 1;
    137  1.42     pooka }
    138  1.42     pooka 
    139   1.1     pooka int
    140   1.1     pooka main(int argc, char *argv[])
    141   1.1     pooka {
    142   1.1     pooka 	struct psshfs_ctx pctx;
    143   1.1     pooka 	struct puffs_usermount *pu;
    144   1.1     pooka 	struct puffs_ops *pops;
    145  1.49     pooka 	struct psshfs_node *root = &pctx.psn_root;
    146  1.49     pooka 	struct puffs_node *pn_root;
    147  1.49     pooka 	puffs_framev_fdnotify_fn notfn;
    148  1.49     pooka 	struct vattr *rva;
    149   1.2     pooka 	mntoptparse_t mp;
    150  1.21       tnn 	char **sshargs;
    151  1.64  jakllsch 	char *user;
    152  1.64  jakllsch 	char *host;
    153  1.64  jakllsch 	char *path;
    154  1.37     pooka 	int mntflags, pflags, ch;
    155  1.37     pooka 	int detach;
    156  1.51     pooka 	int exportfs, refreshival, numconnections;
    157  1.51     pooka 	int nargs;
    158   1.1     pooka 
    159   1.1     pooka 	setprogname(argv[0]);
    160  1.59     pooka 	puffs_unmountonsignal(SIGINT, true);
    161  1.59     pooka 	puffs_unmountonsignal(SIGTERM, true);
    162   1.1     pooka 
    163   1.2     pooka 	if (argc < 3)
    164   1.2     pooka 		usage();
    165   1.2     pooka 
    166  1.56     pooka 	memset(&pctx, 0, sizeof(pctx));
    167  1.37     pooka 	mntflags = pflags = exportfs = nargs = 0;
    168  1.51     pooka 	numconnections = 1;
    169  1.37     pooka 	detach = 1;
    170  1.40     pooka 	refreshival = DEFAULTREFRESH;
    171  1.49     pooka 	notfn = puffs_framev_unmountonclose;
    172  1.21       tnn 	sshargs = NULL;
    173  1.21       tnn 	add_ssharg(&sshargs, &nargs, SSH_PATH);
    174  1.21       tnn 	add_ssharg(&sshargs, &nargs, "-axs");
    175  1.21       tnn 	add_ssharg(&sshargs, &nargs, "-oClearAllForwardings=yes");
    176  1.21       tnn 
    177  1.56     pooka 	while ((ch = getopt(argc, argv, "c:eF:g:o:O:pr:st:u:")) != -1) {
    178   1.2     pooka 		switch (ch) {
    179  1.51     pooka 		case 'c':
    180  1.51     pooka 			numconnections = atoi(optarg);
    181  1.51     pooka 			if (numconnections < 1 || numconnections > 2) {
    182  1.51     pooka 				fprintf(stderr, "%s: only 1 or 2 connections "
    183  1.51     pooka 				    "permitted currently\n", getprogname());
    184  1.51     pooka 				usage();
    185  1.51     pooka 				/*NOTREACHED*/
    186  1.51     pooka 			}
    187  1.51     pooka 			break;
    188  1.11     pooka 		case 'e':
    189  1.13     pooka 			exportfs = 1;
    190  1.11     pooka 			break;
    191  1.47      jmmv 		case 'F':
    192  1.47      jmmv 			add_ssharg(&sshargs, &nargs, "-F");
    193  1.47      jmmv 			add_ssharg(&sshargs, &nargs, optarg);
    194  1.47      jmmv 			break;
    195  1.56     pooka 		case 'g':
    196  1.56     pooka 			pctx.domanglegid = 1;
    197  1.56     pooka 			pctx.manglegid = atoi(optarg);
    198  1.57     pooka 			if (pctx.manglegid == (gid_t)-1)
    199  1.58     pooka 				errx(1, "-1 not allowed for -g");
    200  1.56     pooka 			pctx.mygid = getegid();
    201  1.56     pooka 			break;
    202  1.21       tnn 		case 'O':
    203  1.22       tnn 			add_ssharg(&sshargs, &nargs, "-o");
    204  1.22       tnn 			add_ssharg(&sshargs, &nargs, optarg);
    205  1.21       tnn 			break;
    206   1.2     pooka 		case 'o':
    207   1.2     pooka 			mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags);
    208   1.2     pooka 			if (mp == NULL)
    209   1.2     pooka 				err(1, "getmntopts");
    210   1.2     pooka 			freemntopts(mp);
    211   1.2     pooka 			break;
    212  1.49     pooka 		case 'p':
    213  1.49     pooka 			notfn = psshfs_notify;
    214  1.49     pooka 			break;
    215  1.36     pooka 		case 'r':
    216  1.36     pooka 			max_reads = atoi(optarg);
    217  1.36     pooka 			break;
    218   1.4     pooka 		case 's':
    219  1.37     pooka 			detach = 0;
    220   1.4     pooka 			break;
    221  1.40     pooka 		case 't':
    222  1.40     pooka 			refreshival = atoi(optarg);
    223  1.41     pooka 			if (refreshival < 0 && refreshival != -1)
    224  1.41     pooka 				errx(1, "invalid timeout %d", refreshival);
    225  1.40     pooka 			break;
    226  1.56     pooka 		case 'u':
    227  1.56     pooka 			pctx.domangleuid = 1;
    228  1.56     pooka 			pctx.mangleuid = atoi(optarg);
    229  1.57     pooka 			if (pctx.mangleuid == (uid_t)-1)
    230  1.58     pooka 				errx(1, "-1 not allowed for -u");
    231  1.56     pooka 			pctx.myuid = geteuid();
    232  1.56     pooka 			break;
    233   1.2     pooka 		default:
    234   1.2     pooka 			usage();
    235   1.2     pooka 			/*NOTREACHED*/
    236   1.2     pooka 		}
    237   1.2     pooka 	}
    238   1.2     pooka 	argc -= optind;
    239   1.2     pooka 	argv += optind;
    240   1.2     pooka 
    241   1.4     pooka 	if (pflags & PUFFS_FLAG_OPDUMP)
    242  1.37     pooka 		detach = 0;
    243  1.20     pooka 	pflags |= PUFFS_FLAG_BUILDPATH;
    244  1.20     pooka 	pflags |= PUFFS_KFLAG_WTCACHE | PUFFS_KFLAG_IAONDEMAND;
    245   1.4     pooka 
    246   1.2     pooka 	if (argc != 2)
    247   1.2     pooka 		usage();
    248   1.1     pooka 
    249   1.1     pooka 	PUFFSOP_INIT(pops);
    250   1.1     pooka 
    251   1.1     pooka 	PUFFSOP_SET(pops, psshfs, fs, unmount);
    252   1.1     pooka 	PUFFSOP_SETFSNOP(pops, sync); /* XXX */
    253  1.50     pooka 	PUFFSOP_SET(pops, psshfs, fs, statvfs);
    254  1.11     pooka 	PUFFSOP_SET(pops, psshfs, fs, nodetofh);
    255  1.11     pooka 	PUFFSOP_SET(pops, psshfs, fs, fhtonode);
    256   1.1     pooka 
    257   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, lookup);
    258   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, create);
    259  1.19     pooka 	PUFFSOP_SET(pops, psshfs, node, open);
    260  1.19     pooka 	PUFFSOP_SET(pops, psshfs, node, inactive);
    261   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, readdir);
    262   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, getattr);
    263   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, setattr);
    264   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, mkdir);
    265   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, remove);
    266   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, readlink);
    267   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, rmdir);
    268   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, symlink);
    269   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, rename);
    270   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, read);
    271   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, write);
    272   1.1     pooka 	PUFFSOP_SET(pops, psshfs, node, reclaim);
    273   1.1     pooka 
    274  1.33     pooka 	pu = puffs_init(pops, argv[0], "psshfs", &pctx, pflags);
    275  1.33     pooka 	if (pu == NULL)
    276  1.33     pooka 		err(1, "puffs_init");
    277  1.33     pooka 
    278  1.11     pooka 	pctx.mounttime = time(NULL);
    279  1.40     pooka 	pctx.refreshival = refreshival;
    280  1.51     pooka 	pctx.numconnections = numconnections;
    281   1.1     pooka 
    282  1.64  jakllsch 	user = strdup(argv[0]);
    283  1.64  jakllsch 	if ((host = strrchr(user, '@')) == NULL) {
    284  1.64  jakllsch 		host = user;
    285  1.64  jakllsch 	} else {
    286  1.64  jakllsch 		*host++ = '\0';		/* break at the '@' */
    287  1.64  jakllsch 		if (user[0] == '\0') {
    288  1.64  jakllsch 			fprintf(stderr, "Missing username\n");
    289  1.64  jakllsch 			usage();
    290  1.64  jakllsch 		}
    291  1.64  jakllsch 		add_ssharg(&sshargs, &nargs, "-l");
    292  1.64  jakllsch 		add_ssharg(&sshargs, &nargs, user);
    293  1.64  jakllsch 	}
    294  1.64  jakllsch 
    295  1.64  jakllsch 	if ((path = colon(host)) != NULL) {
    296  1.64  jakllsch 		*path++ = '\0';		/* break at the ':' */
    297  1.64  jakllsch 		pctx.mountpath = path;
    298  1.64  jakllsch 	} else {
    299   1.1     pooka 		pctx.mountpath = ".";
    300  1.64  jakllsch 	}
    301  1.64  jakllsch 
    302  1.64  jakllsch 	host = cleanhostname(host);
    303  1.64  jakllsch 	if (host[0] == '\0') {
    304  1.64  jakllsch 		fprintf(stderr, "Missing hostname\n");
    305  1.64  jakllsch 		usage();
    306  1.64  jakllsch 	}
    307   1.1     pooka 
    308  1.64  jakllsch 	add_ssharg(&sshargs, &nargs, host);
    309  1.21       tnn 	add_ssharg(&sshargs, &nargs, "sftp");
    310  1.49     pooka 	pctx.sshargs = sshargs;
    311  1.49     pooka 
    312  1.49     pooka 	pctx.nextino = 2;
    313  1.49     pooka 	memset(root, 0, sizeof(struct psshfs_node));
    314  1.63  riastrad 	TAILQ_INIT(&root->pw);
    315  1.49     pooka 	pn_root = puffs_pn_new(pu, root);
    316  1.49     pooka 	if (pn_root == NULL)
    317  1.49     pooka 		return errno;
    318  1.49     pooka 	puffs_setroot(pu, pn_root);
    319   1.1     pooka 
    320  1.51     pooka 	puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL, notfn);
    321  1.51     pooka 
    322  1.42     pooka 	signal(SIGHUP, takehup);
    323  1.42     pooka 	puffs_ml_setloopfn(pu, psshfs_loopfn);
    324  1.51     pooka 	if (pssh_connect(pu, PSSHFD_META) == -1)
    325  1.51     pooka 		err(1, "can't connect meta");
    326  1.51     pooka 	if (puffs_framev_addfd(pu, pctx.sshfd,
    327  1.51     pooka 	    PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
    328  1.51     pooka 		err(1, "framebuf addfd meta");
    329  1.51     pooka 	if (numconnections == 2) {
    330  1.51     pooka 		if (pssh_connect(pu, PSSHFD_DATA) == -1)
    331  1.51     pooka 			err(1, "can't connect data");
    332  1.51     pooka 		if (puffs_framev_addfd(pu, pctx.sshfd_data,
    333  1.51     pooka 		    PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
    334  1.51     pooka 			err(1, "framebuf addfd data");
    335  1.51     pooka 	} else {
    336  1.51     pooka 		pctx.sshfd_data = pctx.sshfd;
    337  1.51     pooka 	}
    338   1.4     pooka 
    339  1.13     pooka 	if (exportfs)
    340  1.13     pooka 		puffs_setfhsize(pu, sizeof(struct psshfs_fid),
    341  1.13     pooka 		    PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3);
    342  1.13     pooka 
    343  1.49     pooka 	rva = &pn_root->pn_va;
    344  1.49     pooka 	rva->va_fileid = pctx.nextino++;
    345  1.60     pooka 
    346  1.60     pooka 	/*
    347  1.60     pooka 	 * For root link count, just guess something ridiculously high.
    348  1.61     pooka 	 * Guessing too high has no known adverse effects, but fts(3)
    349  1.60     pooka 	 * doesn't like too low values.  This guess will be replaced
    350  1.60     pooka 	 * with the real value when readdir is first called for
    351  1.60     pooka 	 * the root directory.
    352  1.60     pooka 	 */
    353  1.60     pooka 	rva->va_nlink = 8811;
    354  1.49     pooka 
    355  1.37     pooka 	if (detach)
    356  1.44     pooka 		if (puffs_daemon(pu, 1, 1) == -1)
    357  1.44     pooka 			err(1, "puffs_daemon");
    358  1.37     pooka 
    359  1.38     pooka 	if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1)
    360  1.38     pooka 		err(1, "puffs_mount");
    361  1.39     pooka 	if (puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK) == -1)
    362  1.39     pooka 		err(1, "setblockingmode");
    363  1.39     pooka 
    364  1.37     pooka 	if (puffs_mainloop(pu) == -1)
    365  1.38     pooka 		err(1, "mainloop");
    366  1.48     pooka 	puffs_exit(pu, 1);
    367  1.38     pooka 
    368  1.37     pooka 	return 0;
    369   1.1     pooka }
    370   1.1     pooka 
    371  1.49     pooka #define RETRY_MAX 100
    372  1.49     pooka 
    373  1.49     pooka void
    374  1.49     pooka psshfs_notify(struct puffs_usermount *pu, int fd, int what)
    375  1.49     pooka {
    376  1.49     pooka 	struct psshfs_ctx *pctx = puffs_getspecific(pu);
    377  1.54     pooka 	int nretry, which, newfd, dummy;
    378  1.51     pooka 
    379  1.51     pooka 	if (fd == pctx->sshfd) {
    380  1.51     pooka 		which = PSSHFD_META;
    381  1.51     pooka 	} else {
    382  1.51     pooka 		assert(fd == pctx->sshfd_data);
    383  1.51     pooka 		which = PSSHFD_DATA;
    384  1.51     pooka 	}
    385  1.49     pooka 
    386  1.49     pooka 	if (puffs_getstate(pu) != PUFFS_STATE_RUNNING)
    387  1.49     pooka 		return;
    388  1.49     pooka 
    389  1.49     pooka 	if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) {
    390  1.51     pooka 		puffs_framev_removefd(pu, fd, ECONNRESET);
    391  1.49     pooka 		return;
    392  1.49     pooka 	}
    393  1.51     pooka 	close(fd);
    394  1.49     pooka 
    395  1.54     pooka 	/* deal with zmobies, beware of half-eaten brain */
    396  1.54     pooka 	while (waitpid(-1, &dummy, WNOHANG) > 0)
    397  1.54     pooka 		continue;
    398  1.54     pooka 
    399  1.49     pooka 	for (nretry = 0;;nretry++) {
    400  1.51     pooka 		if ((newfd = pssh_connect(pu, which)) == -1)
    401  1.49     pooka 			goto retry2;
    402  1.49     pooka 
    403  1.51     pooka 		if (puffs_framev_addfd(pu, newfd,
    404  1.49     pooka 		    PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
    405  1.49     pooka 			goto retry1;
    406  1.49     pooka 
    407  1.49     pooka 		break;
    408  1.49     pooka  retry1:
    409  1.49     pooka 		fprintf(stderr, "reconnect failed... ");
    410  1.51     pooka 		close(newfd);
    411  1.49     pooka  retry2:
    412  1.49     pooka 		if (nretry < RETRY_MAX) {
    413  1.53     pooka 			fprintf(stderr, "retry (%d left)\n", RETRY_MAX-nretry);
    414  1.49     pooka 			sleep(nretry);
    415  1.49     pooka 		} else {
    416  1.49     pooka 			fprintf(stderr, "retry count exceeded, going south\n");
    417  1.49     pooka 			exit(1); /* XXXXXXX */
    418  1.49     pooka 		}
    419  1.49     pooka 	}
    420  1.49     pooka }
    421  1.49     pooka 
    422  1.49     pooka static int
    423  1.51     pooka pssh_connect(struct puffs_usermount *pu, int which)
    424   1.1     pooka {
    425  1.51     pooka 	struct psshfs_ctx *pctx = puffs_getspecific(pu);
    426  1.55     pooka 	char * const *sshargs = pctx->sshargs;
    427   1.1     pooka 	int fds[2];
    428   1.1     pooka 	pid_t pid;
    429  1.51     pooka 	int dnfd, x;
    430  1.51     pooka 	int *sshfd;
    431  1.51     pooka 	pid_t *sshpid;
    432  1.51     pooka 
    433  1.51     pooka 	if (which == PSSHFD_META) {
    434  1.51     pooka 		sshfd = &pctx->sshfd;
    435  1.51     pooka 		sshpid = &pctx->sshpid;
    436  1.51     pooka 	} else {
    437  1.51     pooka 		assert(which == PSSHFD_DATA);
    438  1.51     pooka 		sshfd = &pctx->sshfd_data;
    439  1.51     pooka 		sshpid = &pctx->sshpid_data;
    440  1.51     pooka 	}
    441   1.1     pooka 
    442   1.1     pooka 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
    443  1.49     pooka 		return -1;
    444   1.1     pooka 
    445   1.1     pooka 	pid = fork();
    446   1.1     pooka 	switch (pid) {
    447   1.1     pooka 	case -1:
    448  1.49     pooka 		return -1;
    449   1.1     pooka 		/*NOTREACHED*/
    450   1.1     pooka 	case 0: /* child */
    451   1.1     pooka 		if (dup2(fds[0], STDIN_FILENO) == -1)
    452   1.1     pooka 			err(1, "child dup2");
    453   1.1     pooka 		if (dup2(fds[0], STDOUT_FILENO) == -1)
    454   1.1     pooka 			err(1, "child dup2");
    455   1.1     pooka 		close(fds[0]);
    456   1.1     pooka 		close(fds[1]);
    457  1.28     pooka 
    458  1.28     pooka 		dnfd = open(_PATH_DEVNULL, O_RDWR);
    459  1.28     pooka 		if (dnfd != -1)
    460  1.28     pooka 			dup2(dnfd, STDERR_FILENO);
    461  1.28     pooka 
    462   1.1     pooka 		execvp(sshargs[0], sshargs);
    463  1.51     pooka 		/*NOTREACHED*/
    464   1.1     pooka 		break;
    465   1.1     pooka 	default:
    466  1.51     pooka 		*sshpid = pid;
    467  1.51     pooka 		*sshfd = fds[1];
    468   1.1     pooka 		close(fds[0]);
    469   1.1     pooka 		break;
    470   1.1     pooka 	}
    471  1.49     pooka 
    472  1.51     pooka 	if (psshfs_handshake(pu, *sshfd) != 0)
    473  1.62     pooka 		errx(1, "handshake failed, server does not support sftp?");
    474  1.51     pooka 	x = 1;
    475  1.51     pooka 	if (ioctl(*sshfd, FIONBIO, &x) == -1)
    476  1.51     pooka 		err(1, "nonblocking descriptor %d", which);
    477  1.51     pooka 
    478  1.51     pooka 	return *sshfd;
    479   1.1     pooka }
    480  1.42     pooka 
    481  1.42     pooka static void *
    482  1.42     pooka invalone(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
    483  1.42     pooka {
    484  1.42     pooka 	struct psshfs_node *psn = pn->pn_data;
    485  1.42     pooka 
    486  1.42     pooka 	psn->attrread = 0;
    487  1.42     pooka 	psn->dentread = 0;
    488  1.43     pooka 	psn->slread = 0;
    489  1.42     pooka 
    490  1.42     pooka 	return NULL;
    491  1.42     pooka }
    492  1.42     pooka 
    493  1.42     pooka static void
    494  1.42     pooka psshfs_loopfn(struct puffs_usermount *pu)
    495  1.42     pooka {
    496  1.42     pooka 
    497  1.42     pooka 	if (sighup) {
    498  1.42     pooka 		puffs_pn_nodewalk(pu, invalone, NULL);
    499  1.42     pooka 		sighup = 0;
    500  1.42     pooka 	}
    501  1.42     pooka }
    502