src/cmd: Add a repurposed import(4), called `9import', to the ports.

The code is adapted from Plan 9's import(4); this allows us to speak
that protocol. We don't currently support AAN (in the works) or
TLS/SSL.

Thanks to David for help with the man page, testing, and development.

R=0intro, rsc
CC=plan9port.codebot
http://codereview.appspot.com/6458100
This commit is contained in:
Akshat Kumar 2012-09-24 10:35:01 -04:00 committed by Russ Cox
parent 37f8ed2410
commit ac3ba726f9
3 changed files with 319 additions and 0 deletions

View file

@ -5,6 +5,7 @@
Abhishek Kulkarni <adkulkar@umail.iu.edu>
Albert Lee <trisk@acm.jhu.edu>
Akshat Kumar <seed@mail.nanosouffle.net>
André Günther <Andre.G@gmx.de>
Anthony Martin <ality@pbrane.org>
Anthony Sorace <a@9srv.net>

79
man/man4/9import.4 Normal file
View file

@ -0,0 +1,79 @@
.TH 9IMPORT 4
.SH NAME
9import \- import a name space from a remote system
.SH SYNOPSIS
.B 9import
[
.I options
]
.I system
.I file
[
.I mountpoint
]
.SH DESCRIPTION
The
.I 9import
tool allows an arbitrary
.I file
on a remote
.I system,
with the capability of running the Plan 9
.IR exportfs (4)
service,
to be imported into the local name space.
Usually
.I file
is a directory, so the complete
file tree under the directory is made available.
.PP
A process is started on the
remote machine, with authority of the user of
.IR 9import ,
to perform work for the local machine using the
.IR exportfs (4)
service.
The default port used is TCP 17007.
If
.I mountpoint
is omitted, then
.I 9import
uses the name of the remote
.I file
as the local mount point.
.PP
The options are:
.TF "-s namexxx"
.PD
.TP
.B -A
Skip the authentication protocol.
This is useful for connecting to foreign systems like Inferno.
.TP
.B -k \fIkeypattern
Use
.I keypattern
to select a key to authenticate to the remote side
(see
.IR auth (2)).
.TP
.B -p
Push the
.IR aan (8)
filter onto the connection to protect against
temporary network outages.
.TP
.B -s \fIname
Post the connection's mountable file descriptor as
.BI /srv/ name\fR.
.SH SOURCE
.B \*9/src/cmd/9import.c
.SH SEE ALSO
.IR srv (4),
.IR aan (8),
.IR listen1 (8),
.B cs
in
.IR ndb (7)
.SH BUGS
Encryption is not implemented.

239
src/cmd/9import.c Normal file
View file

@ -0,0 +1,239 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <thread.h>
enum {
Encnone,
Encssl,
Enctls,
};
static char *encprotos[] = {
[Encnone] = "clear",
[Encssl] = "ssl",
[Enctls] = "tls",
nil,
};
char *keyspec = "";
char *filterp;
char *ealgs = "rc4_256 sha1";
int encproto = Encnone;
AuthInfo *ai;
int debug;
int doauth = 1;
int timedout;
int connectez(char*, char*);
void sysfatal(char*, ...);
void usage(void);
int filter(int, char *, char *);
int
catcher(void *v, char *msg)
{
timedout = 1;
if(strcmp(msg, "alarm") == 0)
return 1;
return 0;
}
static int
lookup(char *s, char *l[])
{
int i;
for (i = 0; l[i] != 0; i++)
if (strcmp(l[i], s) == 0)
return i;
return -1;
}
static char*
srvname(char *addr)
{
int i;
for(i=0; i<strlen(addr); i++){
if(addr[i] == '!')
addr[i] = ':';
}
return addr;
}
void
threadmain(int argc, char **argv)
{
char *mntpt, *srvpost, srvfile[64];
int fd;
quotefmtinstall();
srvpost = nil;
ARGBEGIN{
case 'A':
doauth = 0;
break;
case 'd':
debug++;
break;
case 'E':
if ((encproto = lookup(EARGF(usage()), encprotos)) < 0)
usage();
break;
case 'e':
ealgs = EARGF(usage());
if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
ealgs = nil;
break;
case 'k':
keyspec = EARGF(usage());
break;
case 'p':
filterp = unsharp("#9/bin/aan");
break;
case 's':
srvpost = EARGF(usage());
break;
default:
usage();
}ARGEND;
mntpt = 0; /* to shut up compiler */
switch(argc) {
case 2:
mntpt = argv[1];
break;
case 3:
mntpt = argv[2];
break;
default:
usage();
}
if(encproto != Encnone)
sysfatal("%s: tls and ssl have not yet been implemented", argv[0]);
threadnotify(catcher, 1);
alarm(60*1000);
fd = connectez(argv[0], argv[1]);
fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter",
encprotos[encproto]);
if (filterp)
fd = filter(fd, filterp, argv[0]);
if(srvpost == nil)
srvpost = srvname(argv[0]);
sprint(srvfile, "%s", srvpost);
if(post9pservice(fd, srvfile, mntpt) < 0)
sysfatal("can't post %s: %r", argv[1]);
alarm(0);
threadexitsall(0);
}
/* the name "connect" is special */
int
connectez(char *system, char *tree)
{
char buf[ERRMAX], *na;
int fd, n;
char *authp;
na = netmkaddr(system, "tcp", "exportfs");
threadsetname("dial %s", na);
if((fd = dial(na, nil, nil, nil)) < 0)
sysfatal("can't dial %s: %r", system);
if(doauth){
authp = "p9any";
threadsetname("auth_proxy auth_getkey proto=%q role=client %s",
authp, keyspec);
ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s",
authp, keyspec);
if(ai == nil)
sysfatal("%r: %s", system);
}
threadsetname("writing tree name %s", tree);
n = write(fd, tree, strlen(tree));
if(n < 0)
sysfatal("can't write tree: %r");
strcpy(buf, "can't read tree");
threadsetname("awaiting OK for %s", tree);
n = read(fd, buf, sizeof buf - 1);
if(n!=2 || buf[0]!='O' || buf[1]!='K'){
if (timedout)
sysfatal("timed out connecting to %s", na);
buf[sizeof buf - 1] = '\0';
sysfatal("bad remote tree: %s", buf);
}
return fd;
}
void
usage(void)
{
fprint(2, "usage: 9import [-A] [-E clear|ssl|tls] "
"[-e 'crypt auth'|clear] [-k keypattern] [-p] [-s srv] host remotefs [mountpoint]\n");
threadexitsall("usage");
}
/* Network on fd1, mount driver on fd0 */
int
filter(int fd, char *cmd, char *host)
{
int p[2], len, argc;
char newport[256], buf[256], *s;
char *argv[16], *file, *pbuf;
if ((len = read(fd, newport, sizeof newport - 1)) < 0)
sysfatal("filter: cannot write port; %r");
newport[len] = '\0';
if ((s = strchr(newport, '!')) == nil)
sysfatal("filter: illegally formatted port %s", newport);
strecpy(buf, buf+sizeof buf, netmkaddr(host, "tcp", "0"));
pbuf = strrchr(buf, '!');
strecpy(pbuf, buf+sizeof buf, s);
if(debug)
fprint(2, "filter: remote port %s\n", newport);
argc = tokenize(cmd, argv, nelem(argv)-2);
if (argc == 0)
sysfatal("filter: empty command");
argv[argc++] = "-c";
argv[argc++] = buf;
argv[argc] = nil;
file = argv[0];
if (s = strrchr(argv[0], '/'))
argv[0] = s+1;
if(pipe(p) < 0)
sysfatal("pipe: %r");
switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
case -1:
sysfatal("rfork record module: %r");
case 0:
dup(p[0], 1);
dup(p[0], 0);
close(p[0]);
close(p[1]);
exec(file, argv);
sysfatal("exec record module: %r");
default:
close(fd);
close(p[0]);
}
return p[1];
}