1*18b2a948Smsaitoh /* $NetBSD: psshfs.c,v 1.67 2021/12/05 08:11:39 msaitoh Exp $ */
2c3ef8ea5Spooka
3c3ef8ea5Spooka /*
4dac06153Spooka * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
5c3ef8ea5Spooka *
6c3ef8ea5Spooka * Redistribution and use in source and binary forms, with or without
7c3ef8ea5Spooka * modification, are permitted provided that the following conditions
8c3ef8ea5Spooka * are met:
9c3ef8ea5Spooka * 1. Redistributions of source code must retain the above copyright
10c3ef8ea5Spooka * notice, this list of conditions and the following disclaimer.
11c3ef8ea5Spooka * 2. Redistributions in binary form must reproduce the above copyright
12c3ef8ea5Spooka * notice, this list of conditions and the following disclaimer in the
13c3ef8ea5Spooka * documentation and/or other materials provided with the distribution.
14c3ef8ea5Spooka *
15c3ef8ea5Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16c3ef8ea5Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17c3ef8ea5Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18c3ef8ea5Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c3ef8ea5Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c3ef8ea5Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21c3ef8ea5Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c3ef8ea5Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c3ef8ea5Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c3ef8ea5Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c3ef8ea5Spooka * SUCH DAMAGE.
26c3ef8ea5Spooka */
27c3ef8ea5Spooka
28c3ef8ea5Spooka /*
29c3ef8ea5Spooka * psshfs: puffs sshfs
30c3ef8ea5Spooka *
31c3ef8ea5Spooka * psshfs implements sshfs functionality on top of puffs making it
32*18b2a948Smsaitoh * possible to mount a filesystem through the sftp service.
33c3ef8ea5Spooka *
34c3ef8ea5Spooka * psshfs can execute multiple operations in "parallel" by using the
35c3ef8ea5Spooka * puffs_cc framework for continuations.
36c3ef8ea5Spooka *
37c3ef8ea5Spooka * Concurrency control is handled currently by vnode locking (this
38c3ef8ea5Spooka * will change in the future). Context switch locations are easy to
390e7bdfc1Spooka * find by grepping for puffs_framebuf_enqueue_cc().
40c3ef8ea5Spooka */
41c3ef8ea5Spooka
42c3ef8ea5Spooka #include <sys/cdefs.h>
43c3ef8ea5Spooka #ifndef lint
44*18b2a948Smsaitoh __RCSID("$NetBSD: psshfs.c,v 1.67 2021/12/05 08:11:39 msaitoh Exp $");
45c3ef8ea5Spooka #endif /* !lint */
46c3ef8ea5Spooka
47c3ef8ea5Spooka #include <sys/types.h>
48d6c25c2bSpooka #include <sys/wait.h>
494f048a36Schristos #include <sys/socket.h>
50c3ef8ea5Spooka
514f048a36Schristos #include <stdio.h>
52c3ef8ea5Spooka #include <assert.h>
53c3ef8ea5Spooka #include <err.h>
54c3ef8ea5Spooka #include <errno.h>
55a67e4ce3Spooka #include <mntopts.h>
56464b354eSpooka #include <paths.h>
57c3ef8ea5Spooka #include <poll.h>
58c3ef8ea5Spooka #include <puffs.h>
59c3ef8ea5Spooka #include <signal.h>
60c3ef8ea5Spooka #include <stdlib.h>
61c3ef8ea5Spooka #include <util.h>
62c3ef8ea5Spooka #include <unistd.h>
63c3ef8ea5Spooka
64c3ef8ea5Spooka #include "psshfs.h"
65c3ef8ea5Spooka
668ff91531Spooka static int pssh_connect(struct puffs_usermount *, int);
67c5afd8dcSpooka static void psshfs_loopfn(struct puffs_usermount *);
68bec77c5fSjoerg __dead static void usage(void);
693c644b8aSjakllsch static char * cleanhostname(char *);
703c644b8aSjakllsch static char * colon(char *);
71de048bdaSpooka static void add_ssharg(char ***, int *, const char *);
72f423bfeeSpooka static void psshfs_notify(struct puffs_usermount *, int, int);
73c3ef8ea5Spooka
74c3ef8ea5Spooka #define SSH_PATH "/usr/bin/ssh"
75c3ef8ea5Spooka
768543b6baSpooka unsigned int max_reads;
77c5afd8dcSpooka static int sighup;
788543b6baSpooka
793c644b8aSjakllsch static char *
cleanhostname(char * host)803c644b8aSjakllsch cleanhostname(char *host)
813c644b8aSjakllsch {
823c644b8aSjakllsch if (*host == '[' && host[strlen(host) - 1] == ']') {
833c644b8aSjakllsch host[strlen(host) - 1] = '\0';
843c644b8aSjakllsch return (host + 1);
853c644b8aSjakllsch } else
863c644b8aSjakllsch return host;
873c644b8aSjakllsch }
883c644b8aSjakllsch
893c644b8aSjakllsch static char *
colon(char * cp)903c644b8aSjakllsch colon(char *cp)
913c644b8aSjakllsch {
923c644b8aSjakllsch int flag = 0;
933c644b8aSjakllsch
943c644b8aSjakllsch if (*cp == '[')
953c644b8aSjakllsch flag = 1;
963c644b8aSjakllsch
973c644b8aSjakllsch for (; *cp; ++cp) {
983c644b8aSjakllsch if (*cp == '@' && *(cp+1) == '[')
993c644b8aSjakllsch flag = 1;
1003c644b8aSjakllsch if (*cp == ']' && *(cp+1) == ':' && flag)
1013c644b8aSjakllsch return (cp+1);
1023c644b8aSjakllsch if (*cp == ':' && !flag)
1033c644b8aSjakllsch return (cp);
1043c644b8aSjakllsch if (*cp == '/')
1053c644b8aSjakllsch return NULL;
1063c644b8aSjakllsch }
1073c644b8aSjakllsch return NULL;
1083c644b8aSjakllsch }
1093c644b8aSjakllsch
110a67e4ce3Spooka static void
add_ssharg(char *** sshargs,int * nargs,const char * arg)111de048bdaSpooka add_ssharg(char ***sshargs, int *nargs, const char *arg)
112edbbe0d8Stnn {
113edbbe0d8Stnn
114edbbe0d8Stnn *sshargs = realloc(*sshargs, (*nargs + 2) * sizeof(char*));
115edbbe0d8Stnn if (!*sshargs)
116edbbe0d8Stnn err(1, "realloc");
117de048bdaSpooka (*sshargs)[(*nargs)++] = estrdup(arg);
118edbbe0d8Stnn (*sshargs)[*nargs] = NULL;
119edbbe0d8Stnn }
120edbbe0d8Stnn
121edbbe0d8Stnn static void
usage(void)122bec77c5fSjoerg usage(void)
123a67e4ce3Spooka {
124a67e4ce3Spooka
1253c246dfdSpooka fprintf(stderr, "usage: %s "
1268ff91531Spooka "[-ceprst] [-F configfile] [-O sshopt=value] [-o opts] "
127d96be1e1Sjmmv "user@host:path mountpath\n",
128c921b474Spooka getprogname());
1293c246dfdSpooka exit(1);
130a67e4ce3Spooka }
131a67e4ce3Spooka
132c5afd8dcSpooka static void
takehup(int sig)133c5afd8dcSpooka takehup(int sig)
134c5afd8dcSpooka {
135c5afd8dcSpooka
136c5afd8dcSpooka sighup = 1;
137c5afd8dcSpooka }
138c5afd8dcSpooka
139c3ef8ea5Spooka int
main(int argc,char * argv[])140c3ef8ea5Spooka main(int argc, char *argv[])
141c3ef8ea5Spooka {
142c3ef8ea5Spooka struct psshfs_ctx pctx;
143c3ef8ea5Spooka struct puffs_usermount *pu;
144c3ef8ea5Spooka struct puffs_ops *pops;
145f423bfeeSpooka struct psshfs_node *root = &pctx.psn_root;
146f423bfeeSpooka struct puffs_node *pn_root;
147f423bfeeSpooka puffs_framev_fdnotify_fn notfn;
148f423bfeeSpooka struct vattr *rva;
149a67e4ce3Spooka mntoptparse_t mp;
150edbbe0d8Stnn char **sshargs;
1513c644b8aSjakllsch char *user;
1523c644b8aSjakllsch char *host;
1533c644b8aSjakllsch char *path;
1544b0f2948Spooka int mntflags, pflags, ch;
1554b0f2948Spooka int detach;
1568ff91531Spooka int exportfs, refreshival, numconnections;
1578ff91531Spooka int nargs;
158c3ef8ea5Spooka
159c3ef8ea5Spooka setprogname(argv[0]);
160ef38ca99Spooka puffs_unmountonsignal(SIGINT, true);
161ef38ca99Spooka puffs_unmountonsignal(SIGTERM, true);
162c3ef8ea5Spooka
163a67e4ce3Spooka if (argc < 3)
164a67e4ce3Spooka usage();
165a67e4ce3Spooka
166c4291c19Spooka memset(&pctx, 0, sizeof(pctx));
1674b0f2948Spooka mntflags = pflags = exportfs = nargs = 0;
1688ff91531Spooka numconnections = 1;
1694b0f2948Spooka detach = 1;
170a56f46a5Spooka refreshival = DEFAULTREFRESH;
171f423bfeeSpooka notfn = puffs_framev_unmountonclose;
172edbbe0d8Stnn sshargs = NULL;
173edbbe0d8Stnn add_ssharg(&sshargs, &nargs, SSH_PATH);
174edbbe0d8Stnn add_ssharg(&sshargs, &nargs, "-axs");
175edbbe0d8Stnn add_ssharg(&sshargs, &nargs, "-oClearAllForwardings=yes");
176edbbe0d8Stnn
177c4291c19Spooka while ((ch = getopt(argc, argv, "c:eF:g:o:O:pr:st:u:")) != -1) {
178a67e4ce3Spooka switch (ch) {
1798ff91531Spooka case 'c':
1808ff91531Spooka numconnections = atoi(optarg);
1818ff91531Spooka if (numconnections < 1 || numconnections > 2) {
1828ff91531Spooka fprintf(stderr, "%s: only 1 or 2 connections "
1838ff91531Spooka "permitted currently\n", getprogname());
1848ff91531Spooka usage();
1858ff91531Spooka /*NOTREACHED*/
1868ff91531Spooka }
1878ff91531Spooka break;
188bf4e539fSpooka case 'e':
189b173dac6Spooka exportfs = 1;
190bf4e539fSpooka break;
191d96be1e1Sjmmv case 'F':
192d96be1e1Sjmmv add_ssharg(&sshargs, &nargs, "-F");
193d96be1e1Sjmmv add_ssharg(&sshargs, &nargs, optarg);
194d96be1e1Sjmmv break;
195c4291c19Spooka case 'g':
196c4291c19Spooka pctx.domanglegid = 1;
197c4291c19Spooka pctx.manglegid = atoi(optarg);
198754f939dSpooka if (pctx.manglegid == (gid_t)-1)
199eac396bbSpooka errx(1, "-1 not allowed for -g");
200c4291c19Spooka pctx.mygid = getegid();
201c4291c19Spooka break;
202edbbe0d8Stnn case 'O':
203098bf956Stnn add_ssharg(&sshargs, &nargs, "-o");
204098bf956Stnn add_ssharg(&sshargs, &nargs, optarg);
205edbbe0d8Stnn break;
206a67e4ce3Spooka case 'o':
207a67e4ce3Spooka mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags);
208a67e4ce3Spooka if (mp == NULL)
209a67e4ce3Spooka err(1, "getmntopts");
210a67e4ce3Spooka freemntopts(mp);
211a67e4ce3Spooka break;
212f423bfeeSpooka case 'p':
213f423bfeeSpooka notfn = psshfs_notify;
214f423bfeeSpooka break;
2158543b6baSpooka case 'r':
2168543b6baSpooka max_reads = atoi(optarg);
2178543b6baSpooka break;
218c921b474Spooka case 's':
2194b0f2948Spooka detach = 0;
220c921b474Spooka break;
221a56f46a5Spooka case 't':
222a56f46a5Spooka refreshival = atoi(optarg);
2237dc67449Spooka if (refreshival < 0 && refreshival != -1)
2247dc67449Spooka errx(1, "invalid timeout %d", refreshival);
225a56f46a5Spooka break;
226c4291c19Spooka case 'u':
227c4291c19Spooka pctx.domangleuid = 1;
228c4291c19Spooka pctx.mangleuid = atoi(optarg);
229754f939dSpooka if (pctx.mangleuid == (uid_t)-1)
230eac396bbSpooka errx(1, "-1 not allowed for -u");
231c4291c19Spooka pctx.myuid = geteuid();
232c4291c19Spooka break;
233a67e4ce3Spooka default:
234a67e4ce3Spooka usage();
235a67e4ce3Spooka /*NOTREACHED*/
236a67e4ce3Spooka }
237a67e4ce3Spooka }
238a67e4ce3Spooka argc -= optind;
239a67e4ce3Spooka argv += optind;
240a67e4ce3Spooka
241c921b474Spooka if (pflags & PUFFS_FLAG_OPDUMP)
2424b0f2948Spooka detach = 0;
243dca252d8Spooka pflags |= PUFFS_FLAG_BUILDPATH;
244dca252d8Spooka pflags |= PUFFS_KFLAG_WTCACHE | PUFFS_KFLAG_IAONDEMAND;
245c921b474Spooka
246a67e4ce3Spooka if (argc != 2)
247a67e4ce3Spooka usage();
248c3ef8ea5Spooka
249c3ef8ea5Spooka PUFFSOP_INIT(pops);
250c3ef8ea5Spooka
251c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, fs, unmount);
252c3ef8ea5Spooka PUFFSOP_SETFSNOP(pops, sync); /* XXX */
25372d8b8b6Spooka PUFFSOP_SET(pops, psshfs, fs, statvfs);
254bf4e539fSpooka PUFFSOP_SET(pops, psshfs, fs, nodetofh);
255bf4e539fSpooka PUFFSOP_SET(pops, psshfs, fs, fhtonode);
256c3ef8ea5Spooka
257c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, lookup);
258c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, create);
259ded3a0bfSpooka PUFFSOP_SET(pops, psshfs, node, open);
260ded3a0bfSpooka PUFFSOP_SET(pops, psshfs, node, inactive);
261c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, readdir);
262c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, getattr);
263c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, setattr);
264c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, mkdir);
265c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, remove);
266c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, readlink);
267c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, rmdir);
268c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, symlink);
269c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, rename);
270c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, read);
271c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, write);
272c3ef8ea5Spooka PUFFSOP_SET(pops, psshfs, node, reclaim);
273c3ef8ea5Spooka
27408db7d75Spooka pu = puffs_init(pops, argv[0], "psshfs", &pctx, pflags);
27508db7d75Spooka if (pu == NULL)
27608db7d75Spooka err(1, "puffs_init");
27708db7d75Spooka
278bf4e539fSpooka pctx.mounttime = time(NULL);
279a56f46a5Spooka pctx.refreshival = refreshival;
2808ff91531Spooka pctx.numconnections = numconnections;
281c3ef8ea5Spooka
2823c644b8aSjakllsch user = strdup(argv[0]);
2833c644b8aSjakllsch if ((host = strrchr(user, '@')) == NULL) {
2843c644b8aSjakllsch host = user;
2853c644b8aSjakllsch } else {
2863c644b8aSjakllsch *host++ = '\0'; /* break at the '@' */
2873c644b8aSjakllsch if (user[0] == '\0') {
2883c644b8aSjakllsch fprintf(stderr, "Missing username\n");
2893c644b8aSjakllsch usage();
2903c644b8aSjakllsch }
2913c644b8aSjakllsch add_ssharg(&sshargs, &nargs, "-l");
2923c644b8aSjakllsch add_ssharg(&sshargs, &nargs, user);
2933c644b8aSjakllsch }
294c3ef8ea5Spooka
2953c644b8aSjakllsch if ((path = colon(host)) != NULL) {
2963c644b8aSjakllsch *path++ = '\0'; /* break at the ':' */
2973c644b8aSjakllsch pctx.mountpath = path;
2983c644b8aSjakllsch } else {
2993c644b8aSjakllsch pctx.mountpath = ".";
3003c644b8aSjakllsch }
3013c644b8aSjakllsch
3023c644b8aSjakllsch host = cleanhostname(host);
3033c644b8aSjakllsch if (host[0] == '\0') {
3043c644b8aSjakllsch fprintf(stderr, "Missing hostname\n");
3053c644b8aSjakllsch usage();
3063c644b8aSjakllsch }
3073c644b8aSjakllsch
3083c644b8aSjakllsch add_ssharg(&sshargs, &nargs, host);
309edbbe0d8Stnn add_ssharg(&sshargs, &nargs, "sftp");
310f423bfeeSpooka pctx.sshargs = sshargs;
311f423bfeeSpooka
312f423bfeeSpooka pctx.nextino = 2;
313f423bfeeSpooka memset(root, 0, sizeof(struct psshfs_node));
314f4368f51Sriastradh TAILQ_INIT(&root->pw);
315f423bfeeSpooka pn_root = puffs_pn_new(pu, root);
316f423bfeeSpooka if (pn_root == NULL)
317f423bfeeSpooka return errno;
318f423bfeeSpooka puffs_setroot(pu, pn_root);
319c3ef8ea5Spooka
3208ff91531Spooka puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL, notfn);
3218ff91531Spooka
322c5afd8dcSpooka signal(SIGHUP, takehup);
323c5afd8dcSpooka puffs_ml_setloopfn(pu, psshfs_loopfn);
3248ff91531Spooka if (pssh_connect(pu, PSSHFD_META) == -1)
3258ff91531Spooka err(1, "can't connect meta");
3268ff91531Spooka if (puffs_framev_addfd(pu, pctx.sshfd,
3278ff91531Spooka PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
3288ff91531Spooka err(1, "framebuf addfd meta");
3298ff91531Spooka if (numconnections == 2) {
3308ff91531Spooka if (pssh_connect(pu, PSSHFD_DATA) == -1)
3318ff91531Spooka err(1, "can't connect data");
3328ff91531Spooka if (puffs_framev_addfd(pu, pctx.sshfd_data,
3338ff91531Spooka PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
3348ff91531Spooka err(1, "framebuf addfd data");
3358ff91531Spooka } else {
3368ff91531Spooka pctx.sshfd_data = pctx.sshfd;
3378ff91531Spooka }
338c921b474Spooka
339b173dac6Spooka if (exportfs)
340b173dac6Spooka puffs_setfhsize(pu, sizeof(struct psshfs_fid),
341b173dac6Spooka PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3);
342b173dac6Spooka
343f423bfeeSpooka rva = &pn_root->pn_va;
344f423bfeeSpooka rva->va_fileid = pctx.nextino++;
345046f5845Spooka
346046f5845Spooka /*
347046f5845Spooka * For root link count, just guess something ridiculously high.
348d317936dSpooka * Guessing too high has no known adverse effects, but fts(3)
349046f5845Spooka * doesn't like too low values. This guess will be replaced
350046f5845Spooka * with the real value when readdir is first called for
351046f5845Spooka * the root directory.
352046f5845Spooka */
353046f5845Spooka rva->va_nlink = 8811;
354f423bfeeSpooka
3554b0f2948Spooka if (detach)
3564462e945Spooka if (puffs_daemon(pu, 1, 1) == -1)
3574462e945Spooka err(1, "puffs_daemon");
3584b0f2948Spooka
359ec865a5bSpooka if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1)
360ec865a5bSpooka err(1, "puffs_mount");
361a02fe51bSpooka if (puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK) == -1)
362a02fe51bSpooka err(1, "setblockingmode");
363a02fe51bSpooka
3644b0f2948Spooka if (puffs_mainloop(pu) == -1)
365ec865a5bSpooka err(1, "mainloop");
36684c098feSpooka puffs_exit(pu, 1);
367ec865a5bSpooka
3684b0f2948Spooka return 0;
369c3ef8ea5Spooka }
370c3ef8ea5Spooka
371f423bfeeSpooka #define RETRY_MAX 100
372f423bfeeSpooka
373f423bfeeSpooka void
psshfs_notify(struct puffs_usermount * pu,int fd,int what)374f423bfeeSpooka psshfs_notify(struct puffs_usermount *pu, int fd, int what)
375c3ef8ea5Spooka {
376f423bfeeSpooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
377d6c25c2bSpooka int nretry, which, newfd, dummy;
3788ff91531Spooka
3798ff91531Spooka if (fd == pctx->sshfd) {
3808ff91531Spooka which = PSSHFD_META;
3818ff91531Spooka } else {
3828ff91531Spooka assert(fd == pctx->sshfd_data);
3838ff91531Spooka which = PSSHFD_DATA;
3848ff91531Spooka }
385f423bfeeSpooka
386f423bfeeSpooka if (puffs_getstate(pu) != PUFFS_STATE_RUNNING)
387f423bfeeSpooka return;
388f423bfeeSpooka
389f423bfeeSpooka if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) {
3908ff91531Spooka puffs_framev_removefd(pu, fd, ECONNRESET);
391f423bfeeSpooka return;
392f423bfeeSpooka }
3938ff91531Spooka close(fd);
394f423bfeeSpooka
395d6c25c2bSpooka /* deal with zmobies, beware of half-eaten brain */
396d6c25c2bSpooka while (waitpid(-1, &dummy, WNOHANG) > 0)
397d6c25c2bSpooka continue;
398d6c25c2bSpooka
399f423bfeeSpooka for (nretry = 0;;nretry++) {
4008ff91531Spooka if ((newfd = pssh_connect(pu, which)) == -1)
401f423bfeeSpooka goto retry2;
402f423bfeeSpooka
4038ff91531Spooka if (puffs_framev_addfd(pu, newfd,
404f423bfeeSpooka PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
405f423bfeeSpooka goto retry1;
406f423bfeeSpooka
407f423bfeeSpooka break;
408f423bfeeSpooka retry1:
409f423bfeeSpooka fprintf(stderr, "reconnect failed... ");
4108ff91531Spooka close(newfd);
411f423bfeeSpooka retry2:
412f423bfeeSpooka if (nretry < RETRY_MAX) {
413b5cb6a6cSpooka fprintf(stderr, "retry (%d left)\n", RETRY_MAX-nretry);
414f423bfeeSpooka sleep(nretry);
415f423bfeeSpooka } else {
416f423bfeeSpooka fprintf(stderr, "retry count exceeded, going south\n");
417f423bfeeSpooka exit(1); /* XXXXXXX */
418f423bfeeSpooka }
419f423bfeeSpooka }
420f423bfeeSpooka }
421f423bfeeSpooka
422f423bfeeSpooka static int
pssh_connect(struct puffs_usermount * pu,int which)4238ff91531Spooka pssh_connect(struct puffs_usermount *pu, int which)
424f423bfeeSpooka {
4258ff91531Spooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
426de048bdaSpooka char * const *sshargs = pctx->sshargs;
427c3ef8ea5Spooka int fds[2];
428c3ef8ea5Spooka pid_t pid;
4298ff91531Spooka int dnfd, x;
4308ff91531Spooka int *sshfd;
4318ff91531Spooka pid_t *sshpid;
4328ff91531Spooka
4338ff91531Spooka if (which == PSSHFD_META) {
4348ff91531Spooka sshfd = &pctx->sshfd;
4358ff91531Spooka sshpid = &pctx->sshpid;
4368ff91531Spooka } else {
4378ff91531Spooka assert(which == PSSHFD_DATA);
4388ff91531Spooka sshfd = &pctx->sshfd_data;
4398ff91531Spooka sshpid = &pctx->sshpid_data;
4408ff91531Spooka }
441c3ef8ea5Spooka
442c3ef8ea5Spooka if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
443f423bfeeSpooka return -1;
444c3ef8ea5Spooka
445c3ef8ea5Spooka pid = fork();
446c3ef8ea5Spooka switch (pid) {
447c3ef8ea5Spooka case -1:
448f423bfeeSpooka return -1;
449c3ef8ea5Spooka /*NOTREACHED*/
450c3ef8ea5Spooka case 0: /* child */
451c3ef8ea5Spooka if (dup2(fds[0], STDIN_FILENO) == -1)
452c3ef8ea5Spooka err(1, "child dup2");
453c3ef8ea5Spooka if (dup2(fds[0], STDOUT_FILENO) == -1)
454c3ef8ea5Spooka err(1, "child dup2");
455c3ef8ea5Spooka close(fds[0]);
456c3ef8ea5Spooka close(fds[1]);
457464b354eSpooka
458464b354eSpooka dnfd = open(_PATH_DEVNULL, O_RDWR);
459464b354eSpooka if (dnfd != -1)
460464b354eSpooka dup2(dnfd, STDERR_FILENO);
461464b354eSpooka
462c3ef8ea5Spooka execvp(sshargs[0], sshargs);
4638ff91531Spooka /*NOTREACHED*/
464c3ef8ea5Spooka break;
465c3ef8ea5Spooka default:
4668ff91531Spooka *sshpid = pid;
4678ff91531Spooka *sshfd = fds[1];
468c3ef8ea5Spooka close(fds[0]);
469c3ef8ea5Spooka break;
470c3ef8ea5Spooka }
471f423bfeeSpooka
4728ff91531Spooka if (psshfs_handshake(pu, *sshfd) != 0)
473080506bcSpooka errx(1, "handshake failed, server does not support sftp?");
4748ff91531Spooka x = 1;
4758ff91531Spooka if (ioctl(*sshfd, FIONBIO, &x) == -1)
4768ff91531Spooka err(1, "nonblocking descriptor %d", which);
4778ff91531Spooka
4788ff91531Spooka return *sshfd;
479c3ef8ea5Spooka }
480c5afd8dcSpooka
481c5afd8dcSpooka static void *
invalone(struct puffs_usermount * pu,struct puffs_node * pn,void * arg)482c5afd8dcSpooka invalone(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
483c5afd8dcSpooka {
484c5afd8dcSpooka struct psshfs_node *psn = pn->pn_data;
485c5afd8dcSpooka
486c5afd8dcSpooka psn->attrread = 0;
487c5afd8dcSpooka psn->dentread = 0;
488b0106b7eSpooka psn->slread = 0;
489c5afd8dcSpooka
490c5afd8dcSpooka return NULL;
491c5afd8dcSpooka }
492c5afd8dcSpooka
493c5afd8dcSpooka static void
psshfs_loopfn(struct puffs_usermount * pu)494c5afd8dcSpooka psshfs_loopfn(struct puffs_usermount *pu)
495c5afd8dcSpooka {
496c5afd8dcSpooka
497c5afd8dcSpooka if (sighup) {
498c5afd8dcSpooka puffs_pn_nodewalk(pu, invalone, NULL);
499c5afd8dcSpooka sighup = 0;
500c5afd8dcSpooka }
501c5afd8dcSpooka }
502