/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "stdinc.h" #include "9.h" typedef struct Srv Srv;struct Srv { int fd; int srvfd; char* service; char* mntpnt; Srv* next; Srv* prev;}; static struct { VtLock* lock; Srv* head; Srv* tail;} sbox; static intsrvFd(char* name, int mode, int fd, char** mntpnt){ int n, srvfd; char *p, buf[10]; /* * Drop a file descriptor with given name and mode into /srv. * Create with ORCLOSE and don't close srvfd so it will be removed * automatically on process exit. */ p = smprint("/srv/%s", name); if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ vtMemFree(p); p = smprint("#s/%s", name); if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ vtSetError("create %s: %r", p); vtMemFree(p); return -1; } } n = snprint(buf, sizeof(buf), "%d", fd); if(write(srvfd, buf, n) < 0){ close(srvfd); vtSetError("write %s: %r", p); vtMemFree(p); return -1; } *mntpnt = p; return srvfd;} static voidsrvFree(Srv* srv){ if(srv->prev != nil) srv->prev->next = srv->next; else sbox.head = srv->next; if(srv->next != nil) srv->next->prev = srv->prev; else sbox.tail = srv->prev; if(srv->srvfd != -1) close(srv->srvfd); vtMemFree(srv->service); vtMemFree(srv->mntpnt); vtMemFree(srv);} static Srv*srvAlloc(char* service, int mode, int fd){ Dir *dir; Srv *srv; int srvfd; char *mntpnt; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, service) != 0) continue; /* * If the service exists, but is stale, * free it up and let the name be reused. */ if((dir = dirfstat(srv->srvfd)) != nil){ free(dir); vtSetError("srv: already serving '%s'", service); vtUnlock(sbox.lock); return nil; } srvFree(srv); break; } if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ vtUnlock(sbox.lock); return nil; } close(fd); srv = vtMemAllocZ(sizeof(Srv)); srv->srvfd = srvfd; srv->service = vtStrDup(service); srv->mntpnt = mntpnt; if(sbox.tail != nil){ srv->prev = sbox.tail; sbox.tail->next = srv; } else{ sbox.head = srv; srv->prev = nil; } sbox.tail = srv; vtUnlock(sbox.lock); return srv;} static intcmdSrv(int argc, char* argv[]){ Con *con; Srv *srv; char *usage = "usage: srv [-APWdp] [service]"; int conflags, dflag, fd[2], mode, pflag, r; dflag = 0; pflag = 0; conflags = 0; mode = 0666; ARGBEGIN{ default: return cliError(usage); case 'A': conflags |= ConNoAuthCheck; break; case 'I': conflags |= ConIPCheck; break; case 'N': conflags |= ConNoneAllow; break; case 'P': conflags |= ConNoPermCheck; mode = 0600; break; case 'W': conflags |= ConWstatAllow; mode = 0600; break; case 'd': dflag = 1; break; case 'p': pflag = 1; mode = 0600; break; }ARGEND if(pflag && (conflags&ConNoPermCheck)){ vtSetError("srv: cannot use -P with -p"); return 0; } switch(argc){ default: return cliError(usage); case 0: vtRLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next) consPrint("\t%s\t%d\n", srv->service, srv->srvfd); vtRUnlock(sbox.lock); return 1; case 1: if(!dflag) break; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, argv[0]) != 0) continue; srvFree(srv); break; } vtUnlock(sbox.lock); if(srv == nil){ vtSetError("srv: '%s' not found", argv[0]); return 0; } return 1; } if(pipe(fd) < 0){ vtSetError("srv pipe: %r"); return 0; } if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ close(fd[0]); close(fd[1]); return 0; } if(pflag) r = consOpen(fd[1], srv->srvfd, -1); else{ con = conAlloc(fd[1], srv->mntpnt, conflags); if(con == nil) r = 0; else r = 1; } if(r == 0){ close(fd[1]); vtLock(sbox.lock); srvFree(srv); vtUnlock(sbox.lock); } return r;} intsrvInit(void){ sbox.lock = vtLockAlloc(); cliAddCmd("srv", cmdSrv); return 1;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include "stdinc.h"
#include "9.h"
typedef struct Srv Srv;
struct Srv {
int fd;
int srvfd;
char* service;
char* mntpnt;
Srv* next;
Srv* prev;
};
static struct {
VtLock* lock;
Srv* head;
Srv* tail;
} sbox;
static int
srvFd(char* name, int mode, int fd, char** mntpnt)
{
int n, srvfd;
char *p, buf[10];
/*
* Drop a file descriptor with given name and mode into /srv.
* Create with ORCLOSE and don't close srvfd so it will be removed
* automatically on process exit.
*/
p = smprint("/srv/%s", name);
if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
vtMemFree(p);
p = smprint("#s/%s", name);
if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
vtSetError("create %s: %r", p);
vtMemFree(p);
return -1;
}
}
n = snprint(buf, sizeof(buf), "%d", fd);
if(write(srvfd, buf, n) < 0){
close(srvfd);
vtSetError("write %s: %r", p);
vtMemFree(p);
return -1;
}
*mntpnt = p;
return srvfd;
}
static void
srvFree(Srv* srv)
{
if(srv->prev != nil)
srv->prev->next = srv->next;
else
sbox.head = srv->next;
if(srv->next != nil)
srv->next->prev = srv->prev;
else
sbox.tail = srv->prev;
if(srv->srvfd != -1)
close(srv->srvfd);
vtMemFree(srv->service);
vtMemFree(srv->mntpnt);
vtMemFree(srv);
}
static Srv*
srvAlloc(char* service, int mode, int fd)
{
Dir *dir;
Srv *srv;
int srvfd;
char *mntpnt;
vtLock(sbox.lock);
for(srv = sbox.head; srv != nil; srv = srv->next){
if(strcmp(srv->service, service) != 0)
continue;
/*
* If the service exists, but is stale,
* free it up and let the name be reused.
*/
if((dir = dirfstat(srv->srvfd)) != nil){
free(dir);
vtSetError("srv: already serving '%s'", service);
vtUnlock(sbox.lock);
return nil;
}
srvFree(srv);
break;
}
if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){
vtUnlock(sbox.lock);
return nil;
}
close(fd);
srv = vtMemAllocZ(sizeof(Srv));
srv->srvfd = srvfd;
srv->service = vtStrDup(service);
srv->mntpnt = mntpnt;
if(sbox.tail != nil){
srv->prev = sbox.tail;
sbox.tail->next = srv;
}
else{
sbox.head = srv;
srv->prev = nil;
}
sbox.tail = srv;
vtUnlock(sbox.lock);
return srv;
}
static int
cmdSrv(int argc, char* argv[])
{
Con *con;
Srv *srv;
char *usage = "usage: srv [-APWdp] [service]";
int conflags, dflag, fd[2], mode, pflag, r;
dflag = 0;
pflag = 0;
conflags = 0;
mode = 0666;
ARGBEGIN{
default:
return cliError(usage);
case 'A':
conflags |= ConNoAuthCheck;
break;
case 'I':
conflags |= ConIPCheck;
break;
case 'N':
conflags |= ConNoneAllow;
break;
case 'P':
conflags |= ConNoPermCheck;
mode = 0600;
break;
case 'W':
conflags |= ConWstatAllow;
mode = 0600;
break;
case 'd':
dflag = 1;
break;
case 'p':
pflag = 1;
mode = 0600;
break;
}ARGEND
if(pflag && (conflags&ConNoPermCheck)){
vtSetError("srv: cannot use -P with -p");
return 0;
}
switch(argc){
default:
return cliError(usage);
case 0:
vtRLock(sbox.lock);
for(srv = sbox.head; srv != nil; srv = srv->next)
consPrint("\t%s\t%d\n", srv->service, srv->srvfd);
vtRUnlock(sbox.lock);
return 1;
case 1:
if(!dflag)
break;
vtLock(sbox.lock);
for(srv = sbox.head; srv != nil; srv = srv->next){
if(strcmp(srv->service, argv[0]) != 0)
continue;
srvFree(srv);
break;
}
vtUnlock(sbox.lock);
if(srv == nil){
vtSetError("srv: '%s' not found", argv[0]);
return 0;
}
return 1;
}
if(pipe(fd) < 0){
vtSetError("srv pipe: %r");
return 0;
}
if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){
close(fd[0]); close(fd[1]);
return 0;
}
if(pflag)
r = consOpen(fd[1], srv->srvfd, -1);
else{
con = conAlloc(fd[1], srv->mntpnt, conflags);
if(con == nil)
r = 0;
else
r = 1;
}
if(r == 0){
close(fd[1]);
vtLock(sbox.lock);
srvFree(srv);
vtUnlock(sbox.lock);
}
return r;
}
int
srvInit(void)
{
sbox.lock = vtLockAlloc();
cliAddCmd("srv", cmdSrv);
return 1;
}