plan9fox/sys/src/cmd/dossrv/xfssrv.c
cinap_lenrek a0d4c5e208 make error handling in 9p service loops consistent
when we get eof, stop the loop immidiately and do not
rely on the read to eventually return an error.

when convM2S() fails to decode the message, error out
and stop the loop. there is no point in continuing.
2016-07-24 02:21:32 +02:00

194 lines
3.1 KiB
C

#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "iotrack.h"
#include "dat.h"
#include "dosfs.h"
#include "fns.h"
#include "errstr.h"
#define Reqsize (sizeof(Fcall)+Maxfdata)
Fcall *req;
Fcall *rep;
uchar mdata[Maxiosize];
char repdata[Maxfdata];
uchar statbuf[STATMAX];
int errno;
char errbuf[ERRMAX];
void rmservice(void);
char srvfile[64];
char *deffile;
int doabort;
int trspaces;
void (*fcalls[])(void) = {
[Tversion] rversion,
[Tflush] rflush,
[Tauth] rauth,
[Tattach] rattach,
[Twalk] rwalk,
[Topen] ropen,
[Tcreate] rcreate,
[Tread] rread,
[Twrite] rwrite,
[Tclunk] rclunk,
[Tremove] rremove,
[Tstat] rstat,
[Twstat] rwstat,
};
void
usage(void)
{
fprint(2, "usage: %s [-v] [-s] [-f devicefile] [srvname]\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
int stdio, srvfd, pipefd[2];
rep = malloc(sizeof(Fcall));
req = malloc(Reqsize);
if(rep == nil || req == nil)
panic("out of memory");
stdio = 0;
ARGBEGIN{
case ':':
trspaces = 1;
break;
case 'r':
readonly = 1;
break;
case 'v':
++chatty;
break;
case 'f':
deffile = ARGF();
break;
case 's':
stdio = 1;
break;
case 'p':
doabort = 1;
break;
default:
usage();
}ARGEND
if(argc == 0)
strcpy(srvfile, "#s/dos");
else if(argc == 1)
snprint(srvfile, sizeof srvfile, "#s/%s", argv[0]);
else
usage();
if(stdio){
pipefd[0] = 0;
pipefd[1] = 1;
}else{
close(0);
close(1);
open("/dev/null", OREAD);
open("/dev/null", OWRITE);
if(pipe(pipefd) < 0)
panic("pipe");
srvfd = create(srvfile, OWRITE|ORCLOSE, 0600);
if(srvfd < 0)
panic(srvfile);
fprint(srvfd, "%d", pipefd[0]);
close(pipefd[0]);
atexit(rmservice);
fprint(2, "%s: serving %s\n", argv0, srvfile);
}
srvfd = pipefd[1];
switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC|RFNAMEG)){
case -1:
panic("fork");
default:
_exits(0);
case 0:
break;
}
iotrack_init();
if(!chatty){
close(2);
open("#c/cons", OWRITE);
}
io(srvfd);
exits(0);
}
void
io(int srvfd)
{
int n, pid;
pid = getpid();
fmtinstall('F', fcallfmt);
while((n = read9pmsg(srvfd, mdata, sizeof mdata)) != 0){
if(n < 0)
panic("mount read");
if(convM2S(mdata, n, req) != n)
panic("convM2S format error");
if(chatty)
fprint(2, "dossrv %d:<-%F\n", pid, req);
errno = 0;
if(!fcalls[req->type])
errno = Ebadfcall;
else
(*fcalls[req->type])();
if(errno){
rep->type = Rerror;
rep->ename = xerrstr(errno);
}else{
rep->type = req->type + 1;
rep->fid = req->fid;
}
rep->tag = req->tag;
if(chatty)
fprint(2, "dossrv %d:->%F\n", pid, rep);
n = convS2M(rep, mdata, sizeof mdata);
if(n == 0)
panic("convS2M error on write");
if(write(srvfd, mdata, n) != n)
panic("mount write");
}
chat("server shut down\n");
}
void
rmservice(void)
{
remove(srvfile);
}
char *
xerrstr(int e)
{
if (e < 0 || e >= sizeof errmsg/sizeof errmsg[0])
return "no such error";
if(e == Eerrstr){
errstr(errbuf, sizeof errbuf);
return errbuf;
}
return errmsg[e];
}
int
eqqid(Qid q1, Qid q2)
{
return q1.path == q2.path && q1.type == q2.type && q1.vers == q2.vers;
}