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:
parent
28945b3253
commit
f423bfeed2
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 .
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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*);
|
||||
|
|
Loading…
Reference in New Issue