# /* fingersrv.c */ /* EMACS_MODES: c !fill */ typedef long time_t; /* ugly! */ #include #include #include #include #include #include #include "../h/q.h" #include "../h/task.h" #include "../h/timer.h" #define FINGERSOCK 79 #define WINDOW 1000 #define MAXTIME 120 #define DIR "/etc" #define LOCKNAME "/etc/locks/finger" #define LOCKMODE 0444 #define WHOPROC "/bin/who" #define WHOISPROC "/bin/whois" /* The following macro is a true GROT to fix a problem with stdio: EINTRs are * treated as errors; and once an error occurs on a file no more I/O may be * performed on it. This macro clears the error bit in the case of an * interrupted I/O operation so I/O may continue. */ #define intrptd(fd) (errno != EINTR?FALSE:((fd)->_flag &= ~_IOERR),TRUE) int dbg; task *ftask; event open_done; event spc_avail; event whole_line; char ibuf[BUFSIZ]; char netbuf[BUFSIZ]; char *bufptr = netbuf; extern int us_opnl (), us_cls (), us_tmo (), us_space(), us_fcls (); extern int input (), quit (), death (); extern task *TCPsend; extern int tcpfd; extern int closing; extern int errno; main (argc, argv) int argc; char **argv; { register int pid; register char *proc, *arg; int pd[2]; FILE *rfd; if (argc > 1) dbg = TRUE; chdir (DIR); if (!creat_lock (LOCKNAME)) { printf ("Duplicate daemon exiting\n"); exit (1); } signal (SIGINT, SIG_IGN); signal (SIGTERM, death); if (!tcp_init (512, 0, us_opnl, input, us_cls, us_fcls, us_tmo, us_space)) exit (1); ftask = tk_cur; if (!tcp_lstn (FINGERSOCK, WINDOW)) { exit (0); } while (!tst_and_clr (&open_done)) tk_block (); tm_set (MAXTIME, us_tmo, 0, NULL); while (!tst_and_clr (&whole_line)) tk_block (); if (strlen (netbuf) == 0) { proc = WHOPROC; arg = 0; } else { proc = WHOISPROC; arg = netbuf; } pipe (pd); if ((pid = fork ()) < 0) { printf ("can't fork\n"); exit (1); } else if (pid == 0) { int i; close (1); dup (pd[1]); for (i = 3; i < NOFILE; i++) close (i); execl (proc, proc, arg, 0); printf ("couldnt exec process\n"); } close (pd[1]); rfd = fcons (pd[0], "r"); for (;;) { while (fgets (ibuf, BUFSIZ, rfd) != NULL) tputs (ibuf); if (feof (rfd) || !intrptd (rfd)) break; } tk_yield (); tcp_close (); for (;;) tk_block (); } input (buf, len, urg) char *buf; register int len; int urg; { register char *p, *q; static int crseen = FALSE; p = buf; q = bufptr; if (dbg) puts (p); while (len-- > 0) { if (crseen) { /* need to de-netascify */ crseen = FALSE; if (*p == '\n') { /* don't include the newline */ *q = '\0'; /* null terminate */ bufptr = q; tk_setef (ftask, &whole_line); return; } else { *q++ = '\r'; if (*p != '\0') *q++ = *p; } } else if (*p == '\r') { crseen = TRUE; } else { *q++ = *p; } p++; } *q = '\0'; bufptr = q; } us_tmo () { printf ("Host not responding\n"); quit (); } quit () { tcp_close (); tk_yield (); exit (1); } creat_lock (name) /* Try to create a lock file with the specified name and write our * process id out there. Returns TRUE on success, FALSE on failure. */ char *name; { int fd; /* file descriptor */ FILE *fptr; /* for stdio */ if ((fd = creat (name, LOCKMODE)) < 0) return (FALSE); fptr = fcons (fd, "w"); /* cons up stdio descriptor */ fprintf (fptr, "%d\n", getpid ()); fclose (fptr); return (TRUE); } tputs (str) /* Send the specified string out to the net. Do the appropriate netascii * conversion as it goes. * * Arguments: */ register char *str; { extern task *TCPsend; extern event sendef; if (dbg) puts (str); for (; *str != '\0'; str++) { if (*str == '\n') tputc ('\r'); tputc (*str); if (*str == '\r') tputc ('\0'); } tk_setef (TCPsend, &sendef); } tputc (c) /* Put the specified character out to tcp. If the output buffer is full, * block until reawakened by the tcp (via the us_space routine). * * Arguments: */ char c; /* character to output */ { while (!tc_put (c)) tk_block (); } us_opnl () { if (dbg) printf ("Open\n"); tk_setef (ftask, &open_done); } us_cls () { if (dbg) printf ("Closed\n"); exit (0); } us_fcls () { if (dbg) printf ("Foreign closed\n"); tcp_close (); } us_space () { tk_setef (ftask, &spc_avail); } death () { unlink (LOCKNAME); exit (0); }