Due to a recent encounter with a sucky internet connection, add

experimental option -p, which tries to reestablish the connection
to the sftp server in case it is lost.  This currently has a few
limitations (found in the man page), but generally works in some
use cases.

Better support might eventually emerge, but since that requires a
plunge into the depths of puffs_framebuf, I need quite a bit of
Fernet Branca to build up my courage before attempting it.
This commit is contained in:
pooka 2008-09-06 12:29:57 +00:00
parent 28945b3253
commit f423bfeed2
5 changed files with 130 additions and 48 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fs.c,v 1.16 2008/08/12 19:51:55 pooka Exp $ */
/* $NetBSD: fs.c,v 1.17 2008/09/06 12:29:57 pooka Exp $ */
/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
@ -27,7 +27,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: fs.c,v 1.16 2008/08/12 19:51:55 pooka Exp $");
__RCSID("$NetBSD: fs.c,v 1.17 2008/09/06 12:29:57 pooka Exp $");
#endif /* !lint */
#include <err.h>
@ -42,21 +42,31 @@ __RCSID("$NetBSD: fs.c,v 1.16 2008/08/12 19:51:55 pooka Exp $");
#include "sftp_proto.h"
#define DO_IO(fname, a1, a2, a3, a4, rv) \
do { \
puffs_framebuf_seekset(a2, 0); \
*(a4) = 0; \
rv = fname(a1, a2, a3, a4); \
if (rv || a4 == 0) errx(1, "psshfs_domount io failed %d, %d", rv, *a4)
if (rv || a4 == 0) { \
fprintf(stderr, "psshfs_handshake failed %d (%s) %d\n", \
rv, strerror(rv), *a4); \
return rv ? rv : EPROTO; \
} \
} while (/*CONSTCOND*/0)
#define reterr(str, rv) \
do { \
fprintf str; \
return rv; \
} while (/*CONSTCOND*/0)
int
psshfs_domount(struct puffs_usermount *pu)
psshfs_handshake(struct puffs_usermount *pu)
{
struct psshfs_ctx *pctx = puffs_getspecific(pu);
struct psshfs_node *root = &pctx->psn_root;
struct puffs_framebuf *pb;
struct puffs_pathobj *po_root;
struct puffs_node *pn_root;
struct vattr va;
struct vattr *rva;
struct puffs_framebuf *pb;
struct vattr va, *rva;
char *rootpath;
uint32_t count;
int rv, done;
@ -69,7 +79,8 @@ psshfs_domount(struct puffs_usermount *pu)
puffs_framebuf_recycle(pb);
DO_IO(psbuf_read, pu, pb, pctx->sshfd, &done, rv);
if (psbuf_get_type(pb) != SSH_FXP_VERSION)
errx(1, "invalid server response: %d", psbuf_get_type(pb));
reterr((stderr, "invalid server response: %d",
psbuf_get_type(pb)), EPROTO);
pctx->protover = psbuf_get_reqid(pb);
/* might contain some other stuff, but we're not interested */
@ -83,12 +94,12 @@ psshfs_domount(struct puffs_usermount *pu)
puffs_framebuf_recycle(pb);
DO_IO(psbuf_read, pu, pb, pctx->sshfd, &done, rv);
if (psbuf_get_type(pb) != SSH_FXP_NAME)
errx(1, "invalid server realpath response for \"%s\"",
pctx->mountpath);
reterr((stderr, "invalid server realpath response for \"%s\"",
pctx->mountpath), EPROTO);
if (psbuf_get_4(pb, &count) == -1)
errx(1, "invalid realpath response: count");
reterr((stderr, "invalid realpath response: count"), EPROTO);
if (psbuf_get_str(pb, &rootpath, NULL) == -1)
errx(1, "invalid realpath response: rootpath");
reterr((stderr, "invalid realpath response: rootpath"), EPROTO);
/* stat the rootdir so that we know it's a dir */
psbuf_recycleout(pb);
@ -100,19 +111,16 @@ psshfs_domount(struct puffs_usermount *pu)
rv = psbuf_expect_attrs(pb, &va);
if (rv)
errx(1, "couldn't stat rootpath");
reterr((stderr, "couldn't stat rootpath"), rv);
puffs_framebuf_destroy(pb);
if (puffs_mode2vt(va.va_mode) != VDIR)
errx(1, "remote path (%s) not a directory", rootpath);
reterr((stderr, "remote path (%s) not a directory", rootpath),
ENOTDIR);
pctx->nextino = 2;
memset(root, 0, sizeof(struct psshfs_node));
pn_root = puffs_pn_new(pu, root);
if (pn_root == NULL)
return errno;
puffs_setroot(pu, pn_root);
pn_root = puffs_getroot(pu);
rva = &pn_root->pn_va;
puffs_setvattr(rva, &va);
po_root = puffs_getrootpathobj(pu);
if (po_root == NULL)
@ -120,11 +128,6 @@ psshfs_domount(struct puffs_usermount *pu)
po_root->po_path = rootpath;
po_root->po_len = strlen(rootpath);
rva = &pn_root->pn_va;
puffs_setvattr(rva, &va);
rva->va_fileid = pctx->nextino++;
rva->va_nlink = 0156; /* XXX */
return 0;
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: mount_psshfs.8,v 1.16 2007/12/14 10:56:22 jmmv Exp $
.\" $NetBSD: mount_psshfs.8,v 1.17 2008/09/06 12:29:57 pooka Exp $
.\"
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
.\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd December 14, 2007
.Dd September 6, 2008
.Dt MOUNT_PSSHFS 8
.Os
.Sh NAME
@ -85,6 +85,14 @@ for example
.Fl O Ar Port=22 .
For a list of valid options, see
.Xr ssh_config 5 .
.It Fl p
Preserve connection.
This option makes
.Nm
to try to reconnect to the server if the connection fails.
The option is very experimental and does not preserve open files
or retry current requests and should generally only be used if the
trade-offs are well understood.
.It Fl r Ar max_reads
Limits maximum outstanding read requests for each node to
.Ar max_reads .

View File

@ -1,4 +1,4 @@
/* $NetBSD: psbuf.c,v 1.12 2007/09/06 16:09:10 pooka Exp $ */
/* $NetBSD: psbuf.c,v 1.13 2008/09/06 12:29:57 pooka Exp $ */
/*
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
@ -27,7 +27,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: psbuf.c,v 1.12 2007/09/06 16:09:10 pooka Exp $");
__RCSID("$NetBSD: psbuf.c,v 1.13 2008/09/06 12:29:57 pooka Exp $");
#endif /* !lint */
/*
@ -108,7 +108,7 @@ psbuf_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
winlen = howmuch;
if (puffs_framebuf_getwindow(pb, CUROFF(pb), &win, &winlen)==-1)
return errno;
n = read(fd, win, winlen);
n = recv(fd, win, winlen, MSG_NOSIGNAL);
switch (n) {
case 0:
return ECONNRESET;

View File

@ -1,4 +1,4 @@
/* $NetBSD: psshfs.c,v 1.48 2008/08/11 16:23:58 pooka Exp $ */
/* $NetBSD: psshfs.c,v 1.49 2008/09/06 12:29:57 pooka Exp $ */
/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
@ -41,7 +41,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: psshfs.c,v 1.48 2008/08/11 16:23:58 pooka Exp $");
__RCSID("$NetBSD: psshfs.c,v 1.49 2008/09/06 12:29:57 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>
@ -60,10 +60,11 @@ __RCSID("$NetBSD: psshfs.c,v 1.48 2008/08/11 16:23:58 pooka Exp $");
#include "psshfs.h"
static void pssh_connect(struct psshfs_ctx *, char **);
static int pssh_connect(struct psshfs_ctx *);
static void psshfs_loopfn(struct puffs_usermount *);
static void usage(void);
static void add_ssharg(char ***, int *, char *);
static void psshfs_notify(struct puffs_usermount *, int, int);
#define SSH_PATH "/usr/bin/ssh"
@ -105,6 +106,10 @@ main(int argc, char *argv[])
struct psshfs_ctx pctx;
struct puffs_usermount *pu;
struct puffs_ops *pops;
struct psshfs_node *root = &pctx.psn_root;
struct puffs_node *pn_root;
puffs_framev_fdnotify_fn notfn;
struct vattr *rva;
mntoptparse_t mp;
char **sshargs;
char *userhost;
@ -122,12 +127,13 @@ main(int argc, char *argv[])
mntflags = pflags = exportfs = nargs = 0;
detach = 1;
refreshival = DEFAULTREFRESH;
notfn = puffs_framev_unmountonclose;
sshargs = NULL;
add_ssharg(&sshargs, &nargs, SSH_PATH);
add_ssharg(&sshargs, &nargs, "-axs");
add_ssharg(&sshargs, &nargs, "-oClearAllForwardings=yes");
while ((ch = getopt(argc, argv, "eF:o:O:r:st:")) != -1) {
while ((ch = getopt(argc, argv, "eF:o:O:pr:st:")) != -1) {
switch (ch) {
case 'e':
exportfs = 1;
@ -146,6 +152,9 @@ main(int argc, char *argv[])
err(1, "getmntopts");
freemntopts(mp);
break;
case 'p':
notfn = psshfs_notify;
break;
case 'r':
max_reads = atoi(optarg);
break;
@ -216,28 +225,39 @@ main(int argc, char *argv[])
add_ssharg(&sshargs, &nargs, argv[0]);
add_ssharg(&sshargs, &nargs, "sftp");
pctx.sshargs = sshargs;
pctx.nextino = 2;
memset(root, 0, sizeof(struct psshfs_node));
pn_root = puffs_pn_new(pu, root);
if (pn_root == NULL)
return errno;
puffs_setroot(pu, pn_root);
signal(SIGHUP, takehup);
puffs_ml_setloopfn(pu, psshfs_loopfn);
pssh_connect(&pctx, sshargs);
if (pssh_connect(&pctx) == -1)
err(1, "can't connect");
if (exportfs)
puffs_setfhsize(pu, sizeof(struct psshfs_fid),
PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3);
if (psshfs_domount(pu) != 0)
errx(1, "psshfs_domount");
if (psshfs_handshake(pu) != 0)
errx(1, "psshfs_handshake");
x = 1;
if (ioctl(pctx.sshfd, FIONBIO, &x) == -1)
err(1, "nonblocking descriptor");
puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL,
puffs_framev_unmountonclose);
puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL, notfn);
if (puffs_framev_addfd(pu, pctx.sshfd,
PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
err(1, "framebuf addfd");
rva = &pn_root->pn_va;
rva->va_fileid = pctx.nextino++;
rva->va_nlink = 101; /* XXX */
if (detach)
if (puffs_daemon(pu, 1, 1) == -1)
err(1, "puffs_daemon");
@ -254,20 +274,68 @@ main(int argc, char *argv[])
return 0;
}
static void
pssh_connect(struct psshfs_ctx *pctx, char **sshargs)
#define RETRY_MAX 100
void
psshfs_notify(struct puffs_usermount *pu, int fd, int what)
{
struct psshfs_ctx *pctx = puffs_getspecific(pu);
int x, nretry;
if (puffs_getstate(pu) != PUFFS_STATE_RUNNING)
return;
if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) {
puffs_framev_removefd(pu, pctx->sshfd, ECONNRESET);
return;
}
close(pctx->sshfd);
for (nretry = 0;;nretry++) {
if (pssh_connect(pctx) == -1)
goto retry2;
if (psshfs_handshake(pu) != 0)
goto retry1;
x = 1;
if (ioctl(pctx->sshfd, FIONBIO, &x) == -1)
goto retry1;
if (puffs_framev_addfd(pu, pctx->sshfd,
PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
goto retry1;
break;
retry1:
fprintf(stderr, "reconnect failed... ");
close(pctx->sshfd);
retry2:
if (nretry < RETRY_MAX) {
fprintf(stderr, "retrying\n");
sleep(nretry);
} else {
fprintf(stderr, "retry count exceeded, going south\n");
exit(1); /* XXXXXXX */
}
}
}
static int
pssh_connect(struct psshfs_ctx *pctx)
{
char **sshargs = pctx->sshargs;
int fds[2];
pid_t pid;
int dnfd;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
err(1, "socketpair");
return -1;
pid = fork();
switch (pid) {
case -1:
err(1, "fork");
return -1;
/*NOTREACHED*/
case 0: /* child */
if (dup2(fds[0], STDIN_FILENO) == -1)
@ -289,6 +357,8 @@ pssh_connect(struct psshfs_ctx *pctx, char **sshargs)
close(fds[0]);
break;
}
return 0;
}
static void *

View File

@ -1,4 +1,4 @@
/* $NetBSD: psshfs.h,v 1.33 2007/12/07 14:59:22 pooka Exp $ */
/* $NetBSD: psshfs.h,v 1.34 2008/09/06 12:29:57 pooka Exp $ */
/*
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
@ -151,6 +151,7 @@ struct psshfs_ctx {
int sshfd;
pid_t sshpid;
const char *mountpath;
char **sshargs;
int protover;
uint32_t nextreq;
@ -166,7 +167,7 @@ struct psshfs_ctx {
int refreshival;
};
int psshfs_domount(struct puffs_usermount *);
int psshfs_handshake(struct puffs_usermount *);
int psbuf_read(struct puffs_usermount *, struct puffs_framebuf *,int,int*);
int psbuf_write(struct puffs_usermount *, struct puffs_framebuf *,int,int*);