5 #define NAMELEN 64 /* reasonable upper limit for name elements */
7 typedef struct Service Service;
10 char serv[NAMELEN]; /* name of the service */
11 char remote[3*NAMELEN]; /* address of remote system */
12 char prog[5*NAMELEN+1]; /* program to execute */
15 typedef struct Announce Announce;
24 int readstr(char*, char*, char*, int);
25 void dolisten(char*, char*, int, char*, char*);
26 void newcall(int, char*, char*, Service*);
27 int findserv(char*, char*, Service*, char*);
28 int getserv(char*, char*, Service*);
30 void scandir(char*, char*, char*);
31 void becomenone(void);
32 void listendir(char*, char*, int);
34 char listenlog[] = "listen";
40 Announce *announcements;
48 error("usage: aux/listen [-q] [-n namespace] [-d servdir] [-t trustdir]"
53 * based on libthread's threadsetname, but drags in less library code.
54 * actually just sets the arguments displayed.
57 procsetname(char *fmt, ...)
65 cmdname = vsmprint(fmt, arg);
69 snprint(buf, sizeof buf, "#p/%d/args", getpid());
70 if((fd = open(buf, OWRITE)) >= 0){
71 write(fd, cmdname, strlen(cmdname)+1);
78 main(int argc, char *argv[])
91 cpu = getenv("cputype");
93 error("can't get cputype");
97 servdir = EARGF(usage());
103 trustdir = EARGF(usage());
106 namespace = EARGF(usage());
110 * fixed configuration, no periodic
111 * rescan of the service directory.
119 if(!servdir && !trustdir)
120 servdir = "/bin/service";
122 if(servdir && strlen(servdir) + NAMELEN >= sizeof(s->prog))
123 error("service directory too long");
124 if(trustdir && strlen(trustdir) + NAMELEN >= sizeof(s->prog))
125 error("trusted service directory too long");
137 syslog(0, listenlog, "started on %s", proto);
140 proto = strrchr(proto, '/');
145 listendir(protodir, servdir, 0);
146 listendir(protodir, trustdir, 1);
148 /* command returns */
153 dingdong(void*, char *msg)
155 if(strstr(msg, "alarm") != nil)
161 listendir(char *protodir, char *srvdir, int trusted)
164 char dir[40], err[128];
172 * insulate ourselves from later
173 * changing of console environment variables
174 * erase privileged crypt state
176 switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT|RFENVG|RFNAMEG)) {
185 procsetname("%s %s %s", protodir, srvdir, namespace);
192 scandir(proto, protodir, srvdir);
195 * loop through announcements and process trusted services in
196 * invoker's ns and untrusted in none's.
198 for(a = announcements; a; a = a->next){
204 /* a process per service */
205 switch(pid = rfork(RFFDG|RFPROC)){
207 syslog(1, listenlog, "couldn't fork for %s", a->a);
211 ctl = announce(a->a, dir);
213 errstr(err, sizeof err);
216 "giving up on %s: %r",
218 if(strstr(err, "address in use")
220 exits("addr-in-use");
224 dolisten(proto, dir, ctl, srvdir, a->a);
234 * if not running a fixed configuration,
235 * pick up any children that gave up and
236 * sleep for at least 60 seconds.
237 * If a service process dies in a fixed
238 * configuration what should be done -
239 * nothing? restart? restart after a delay?
240 * - currently just wait for something to
241 * die and delay at least 60 seconds
247 while((wm = wait()) != nil) {
248 for(a = announcements; a; a = a->next)
249 if(a->announced == wm->pid) {
251 if (strstr(wm->msg, "addr-in-use") !=
253 /* don't fill log file */
262 scandir(proto, protodir, srvdir);
264 start = 60 - (time(0)-start);
272 * make a list of all services to announce for
275 addannounce(char *str)
279 /* look for duplicate */
281 for(a = announcements; a; a = a->next){
282 if(strcmp(str, a->a) == 0)
288 a = mallocz(sizeof(*a) + strlen(str) + 1, 1);
291 a->a = ((char*)a)+sizeof(*a);
298 * delete a service for announcement list
301 delannounce(char *str)
305 /* look for service */
307 for(a = announcements; a; a = a->next){
308 if(strcmp(str, a->a) == 0)
314 *l = a->next; /* drop from the list */
315 if (a->announced > 0)
316 postnote(PNPROC, a->announced, "die");
322 ignore(char *srvdir, char *name)
325 char *file = smprint("%s/%s", srvdir, name);
326 Dir *d = dirstat(file);
328 rv = !d || d->length <= 0; /* ignore unless it's non-empty */
335 scandir(char *proto, char *protodir, char *dname)
342 fd = open(dname, OREAD);
346 nlen = strlen(proto);
347 while((n=dirread(fd, &db)) > 0){
350 if(!(db[i].qid.type&QTDIR) &&
351 strncmp(nm, proto, nlen) == 0) {
352 snprint(ds, sizeof ds, "%s!*!%s", protodir,
354 if (ignore(dname, nm))
371 fd = open("#c/user", OWRITE);
372 if(fd < 0 || write(fd, "none", strlen("none")) < 0)
373 error("can't become none");
375 if(newns("none", namespace) < 0)
376 error("can't build namespace");
380 dolisten(char *proto, char *dir, int ctl, char *srvdir, char *dialstr)
386 procsetname("%s %s", dir, dialstr);
389 * wait for a call (or an error)
391 nctl = listen(dir, ndir);
394 syslog(1, listenlog, "listen: %r");
399 * start a subprocess for the connection
401 switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG)){
403 reject(nctl, ndir, "host overloaded");
408 * see if we know the service requested
410 memset(&s, 0, sizeof s);
411 if(!findserv(proto, ndir, &s, srvdir)){
413 syslog(1, listenlog, "%s: unknown service '%s' from '%s': %r",
414 proto, s.serv, s.remote);
415 reject(nctl, ndir, "connection refused");
418 data = accept(nctl, ndir);
420 syslog(1, listenlog, "can't open %s/data: %r", ndir);
423 fprint(nctl, "keepalive");
426 newcall(data, proto, ndir, &s);
436 * look in the service directory for the service.
437 * if the shell script or program is zero-length, ignore it,
438 * thus providing a way to disable a service with a bind.
441 findserv(char *proto, char *dir, Service *s, char *srvdir)
446 if(!getserv(proto, dir, s))
448 snprint(s->prog, sizeof s->prog, "%s/%s", srvdir, s->serv);
449 d = dirstat(s->prog);
450 rv = d && d->length > 0; /* ignore unless it's non-empty */
456 * get the service name out of the local address
459 getserv(char *proto, char *dir, Service *s)
461 char addr[128], *serv, *p;
464 readstr(dir, "remote", s->remote, sizeof(s->remote)-1);
465 if(p = utfrune(s->remote, L'\n'))
468 n = readstr(dir, "local", addr, sizeof(addr)-1);
471 if(p = utfrune(addr, L'\n'))
473 serv = utfrune(addr, L'!');
480 * disallow service names like
481 * ../../usr/user/bin/rc/su
483 if(strlen(serv) +strlen(proto) >= NAMELEN || utfrune(serv, L'/') || *serv == '.')
485 snprint(s->serv, sizeof s->serv, "%s%s", proto, serv);
491 remoteaddr(char *dir)
496 snprint(buf, sizeof buf, "%s/remote", dir);
497 fd = open(buf, OREAD);
500 n = read(fd, buf, sizeof(buf));
504 p = strchr(buf, '!');
513 newcall(int fd, char *proto, char *dir, Service *s)
515 char data[4*NAMELEN];
521 syslog(0, listenlog, "%s call for %s on chan %s (%s)", proto, s->serv, dir, p);
524 syslog(0, listenlog, "%s call for %s on chan %s", proto, s->serv, dir);
527 snprint(data, sizeof data, "%s/data", dir);
528 bind(data, "/dev/cons", MREPL);
537 for(fd=3; fd<20; fd++)
539 execl(s->prog, s->prog, s->serv, proto, dir, nil);
546 syslog(1, listenlog, "%s: %s: %r", proto, s);
551 * read a string from a device
554 readstr(char *dir, char *info, char *s, int len)
557 char buf[3*NAMELEN+4];
559 snprint(buf, sizeof buf, "%s/%s", dir, info);
560 fd = open(buf, OREAD);
564 n = read(fd, s, len-1);