/*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1983, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1983, 1986 Regents of the University of California.\n\
All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)telnetd.c 5.14 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)telnetd.c 5.30 (Berkeley) %G%";
+#endif /* not lint */
/*
- * Stripped-down telnet server.
+ * Telnet server.
*/
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <syslog.h>
#include <ctype.h>
-#define BELL '\07'
-#define BANNER "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s"
-
-#define OPT_DONT 0 /* don't do this option */
-#define OPT_WONT 0 /* won't do this option */
-#define OPT_DO 1 /* do this option */
-#define OPT_WILL 1 /* will do this option */
-#define OPT_ALWAYS_LOOK 2 /* special case for echo */
+#define OPT_NO 0 /* won't do this option */
+#define OPT_YES 1 /* will do this option */
+#define OPT_YES_BUT_ALWAYS_LOOK 2
+#define OPT_NO_BUT_ALWAYS_LOOK 3
char hisopts[256];
char myopts[256];
/* the remote system seems to NOT be an old 4.2 */
int not42 = 1;
+#define BANNER "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r"
-char subbuffer[100], *subpointer, *subend; /* buffer for sub-options */
+ /* buffer for sub-options */
+char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
#define SB_CLEAR() subpointer = subbuffer;
-#define SB_TERM() subend = subpointer;
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
*subpointer++ = (c); \
}
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_EOF() (subpointer >= subend)
int pcc, ncc;
echotoggle, /* last time user entered echo character */
modenegotiated, /* last time operating mode negotiated */
didnetreceive, /* last time we read data from network */
+ ttypeopt, /* ttype will/won't received */
+ ttypesubopt, /* ttype subopt is received */
+ getterminal, /* time started to get terminal information */
gotDM; /* when did we last see a data mark */
} clocks;
-#define settimer(x) clocks.x = clocks.system++
+#define settimer(x) (clocks.x = ++clocks.system)
+#define sequenceIs(x,y) (clocks.x < clocks.y)
\f
main(argc, argv)
char *argv[];
doit(0, &from);
}
+char *terminaltype = 0;
+char *envinit[2];
+int cleanup();
/*
- * Get()
- *
- * Return next character from file descriptor.
+ * ttloop
*
- * This is not meant to be very efficient, since it is only
- * run during startup.
+ * A small subroutine to flush the network output buffer, get some data
+ * from the network, and pass it through the telnet state machine. We
+ * also flush the pty input buffer (by dropping its data) if it becomes
+ * too full.
*/
-Get(f)
-int f; /* the file descriptor */
+void
+ttloop()
{
- char input;
-
- if (read(f, &input, 1) != 1) {
- syslog(LOG_ERR, "read: %m\n");
+ if (nfrontp-nbackp) {
+ netflush();
+ }
+ ncc = read(net, netibuf, sizeof netibuf);
+ if (ncc < 0) {
+ syslog(LOG_INFO, "ttloop: read: %m\n");
+ exit(1);
+ } else if (ncc == 0) {
+ syslog(LOG_INFO, "ttloop: peer died: %m\n");
exit(1);
}
- return input&0xff;
+ netip = netibuf;
+ telrcv(); /* state machine */
+ if (ncc > 0) {
+ pfrontp = pbackp = ptyobuf;
+ telrcv();
+ }
}
-char *terminaltype;
-char *envinit[2];
-int cleanup();
+/*
+ * getterminaltype
+ *
+ * Ask the other end to send along its terminal type.
+ * Output is the variable terminaltype filled in.
+ */
+
+void
+getterminaltype()
+{
+ static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
+
+ settimer(getterminal);
+ bcopy(sbuf, nfrontp, sizeof sbuf);
+ nfrontp += sizeof sbuf;
+ hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
+ while (sequenceIs(ttypeopt, getterminal)) {
+ ttloop();
+ }
+ if (hisopts[TELOPT_TTYPE] == OPT_YES) {
+ static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
+
+ bcopy(sbbuf, nfrontp, sizeof sbbuf);
+ nfrontp += sizeof sbbuf;
+ while (sequenceIs(ttypesubopt, getterminal)) {
+ ttloop();
+ }
+ }
+}
/*
* Get a pty, scan input lines.
struct sgttyb b;
struct hostent *hp;
int c;
- int gotterminaltype = 0;
-
- /*
- * Try to get a terminal type from the foreign host.
- */
-
- {
- static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
-
- terminaltype = 0;
- if (write(f, sbuf, sizeof sbuf) == -1) {
- syslog(LOG_ERR, "write sbuf: %m\n");
- exit(1);
- }
- for (;;) { /* ugly, but we are VERY early */
- while ((c = Get(f)) != IAC) {
- NIACCUM(c);
- }
- if ((c = Get(f)) == WILL) {
- if ((c = Get(f)) == TELOPT_TTYPE) {
- static char sbbuf[] = { IAC, SB, TELOPT_TTYPE,
- TELQUAL_SEND, IAC, SE };
- if (write(f, sbbuf, sizeof sbbuf) == -1) {
- syslog(LOG_ERR, "write sbbuf: %m\n");
- exit(1);
- }
- break;
- } else {
- NIACCUM(IAC);
- NIACCUM(WILL);
- NIACCUM(c);
- }
- } else if (c == WONT) {
- if ((c = Get(f)) == TELOPT_TTYPE) {
- terminaltype = "TERM=network";
- break;
- } else {
- NIACCUM(IAC);
- NIACCUM(WONT);
- NIACCUM(c);
- }
- } else {
- NIACCUM(IAC);
- NIACCUM(c);
- }
- }
- if (!terminaltype) {
- for (;;) {
- while ((c = Get(f)) != IAC) {
- NIACCUM(c);
- }
- if ((c = Get(f)) != SB) {
- NIACCUM(IAC);
- NIACCUM(c);
- } else if ((c = Get(f)) != TELOPT_TTYPE) {
- NIACCUM(IAC);
- NIACCUM(SB);
- NIACCUM(c);
- } else if ((c = Get(f)) != TELQUAL_IS) {
- NIACCUM(IAC);
- NIACCUM(SB);
- NIACCUM(TELOPT_TTYPE);
- NIACCUM(c);
- } else { /* Yaaaay! */
- static char terminalname[5+41] = "TERM=";
-
- terminaltype = terminalname+strlen(terminalname);
-
- while (terminaltype <
- (terminalname + sizeof terminalname-1)) {
- if ((c = Get(f)) == IAC) {
- if ((c = Get(f)) == SE) {
- break; /* done */
- } else {
- *terminaltype++ = IAC; /* ? */
- if (isupper(c)) {
- c = tolower(c);
- }
- *terminaltype++ = c;
- }
- } else {
- if (isupper(c)) {
- c = tolower(c);
- }
- *terminaltype++ = c; /* accumulate name */
- }
- }
- *terminaltype = 0;
- terminaltype = terminalname;
- gotterminaltype = 1;
- break;
- }
- }
- }
- envinit[0] = terminaltype;
- envinit[1] = 0;
- }
for (c = 'p'; c <= 's'; c++) {
struct stat stb;
if (stat(line, &stb) < 0)
break;
for (i = 0; i < 16; i++) {
- line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
- p = open(line, 2);
+ line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+ p = open(line, O_RDWR);
if (p > 0)
goto gotpty;
}
}
t = open(line, O_RDWR);
if (t < 0)
- fatalperror(f, line, errno);
+ fatalperror(f, line);
+ if (fchmod(t, 0))
+ fatalperror(f, line);
+ (void)signal(SIGHUP, SIG_IGN);
+ vhangup();
+ (void)signal(SIGHUP, SIG_DFL);
+ t = open(line, O_RDWR);
+ if (t < 0)
+ fatalperror(f, line);
ioctl(t, TIOCGETP, &b);
b.sg_flags = CRMOD|XTABS|ANYP;
ioctl(t, TIOCSETP, &b);
host = hp->h_name;
else
host = inet_ntoa(who->sin_addr);
+
+ net = f;
+ pty = p;
+
+ /*
+ * get terminal type.
+ */
+ getterminaltype();
+
if ((i = fork()) < 0)
- fatalperror(f, "fork", errno);
+ fatalperror(f, "fork");
if (i)
telnet(f, p);
close(f);
dup2(t, 1);
dup2(t, 2);
close(t);
+ envinit[0] = terminaltype;
+ envinit[1] = 0;
environ = envinit;
/*
* -h : pass on name of host.
+ * WARNING: -h is accepted by login if and only if
+ * getuid() == 0.
* -p : don't clobber the environment (so terminal type stays set).
*/
execl("/bin/login", "login", "-h", host,
- gotterminaltype ? "-p" : 0, 0);
- fatalperror(f, "/bin/login", errno);
+ terminaltype ? "-p" : 0, 0);
+ fatalperror(f, "/bin/login");
/*NOTREACHED*/
}
exit(1);
}
-fatalperror(f, msg, errno)
+fatalperror(f, msg)
int f;
char *msg;
- int errno;
{
char buf[BUFSIZ];
extern char *sys_errlist[];
FD_ZERO(&excepts);
FD_SET(s, &excepts);
value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
- } while ((value == -1) && (errno = EINTR));
+ } while ((value == -1) && (errno == EINTR));
if (value < 0) {
- fatalperror(pty, "select", errno);
+ fatalperror(pty, "select");
}
if (FD_ISSET(s, &excepts)) {
return 1;
telnet(f, p)
{
int on = 1;
- char hostname[32];
+ char hostname[MAXHOSTNAMELEN];
+#define TABBUFSIZ 512
+ char defent[TABBUFSIZ];
+ char defstrs[TABBUFSIZ];
+#undef TABBUFSIZ
+ char *HE;
+ char *HN;
+ char *IM;
- net = f, pty = p;
ioctl(f, FIONBIO, &on);
ioctl(p, FIONBIO, &on);
+ ioctl(p, TIOCPKT, &on);
#if defined(SO_OOBINLINE)
setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
#endif /* defined(SO_OOBINLINE) */
signal(SIGTSTP, SIG_IGN);
+ /*
+ * Ignoring SIGTTOU keeps the kernel from blocking us
+ * in ttioctl() in /sys/tty.c.
+ */
+ signal(SIGTTOU, SIG_IGN);
signal(SIGCHLD, cleanup);
setpgrp(0, 0);
/*
* Request to do remote echo and to suppress go ahead.
*/
- dooption(TELOPT_ECHO);
- dooption(TELOPT_SGA);
+ if (!myopts[TELOPT_ECHO]) {
+ dooption(TELOPT_ECHO);
+ }
+ if (!myopts[TELOPT_SGA]) {
+ dooption(TELOPT_SGA);
+ }
/*
* Is the client side a 4.2 (NOT 4.3) system? We need to know this
* because 4.2 clients are unable to deal with TCP urgent data.
* WE, the server, sends it; it does NOT mean that the client will
* echo the terminal input).
*/
- sprintf(nfrontp, doopt, TELOPT_ECHO);
+ (void) sprintf(nfrontp, doopt, TELOPT_ECHO);
nfrontp += sizeof doopt-2;
- hisopts[TELOPT_ECHO] = OPT_ALWAYS_LOOK;
+ hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
/*
* Show banner that getty never gave.
+ *
+ * We put the banner in the pty input buffer. This way, it
+ * gets carriage return null processing, etc., just like all
+ * other pty --> client data.
*/
+
gethostname(hostname, sizeof (hostname));
- sprintf(nfrontp, BANNER, hostname, "");
- nfrontp += strlen(nfrontp);
+ if (getent(defent, "default") == 1) {
+ char *getstr();
+ char *p=defstrs;
+
+ HE = getstr("he", &p);
+ HN = getstr("hn", &p);
+ IM = getstr("im", &p);
+ if (HN && *HN)
+ strcpy(hostname, HN);
+ edithost(HE, hostname);
+ if (IM && *IM)
+ putf(IM, ptyibuf+1);
+ } else {
+ sprintf(ptyibuf+1, BANNER, hostname);
+ }
+
+ ptyip = ptyibuf+1; /* Prime the pump */
+ pcc = strlen(ptyip); /* ditto */
+
+ /* Clear ptybuf[0] - where the packet information is received */
+ ptyibuf[0] = 0;
/*
* Call telrcv() once to pick up anything received during
*/
if (nfrontp - nbackp || pcc > 0) {
FD_SET(f, &obits);
+ FD_SET(p, &xbits);
} else {
FD_SET(p, &ibits);
}
if (FD_ISSET(net, &ibits)) {
#if !defined(SO_OOBINLINE)
/*
- * In 4.2 (and some early 4.3) systems, the
+ * In 4.2 (and 4.3 beta) systems, the
* OOB indication and data handling in the kernel
* is such that if two separate TCP Urgent requests
* come in, one byte of TCP data will be overlaid.
ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
if ((ncc == -1) && (errno == EINVAL)) {
ncc = read(net, netibuf, sizeof (netibuf));
- if (clocks.didnetreceive < clocks.gotDM) {
+ if (sequenceIs(didnetreceive, gotDM)) {
SYNCHing = stilloob(net);
}
}
/*
* Something to read from the pty...
*/
+ if (FD_ISSET(p, &xbits)) {
+ if (read(p, ptyibuf, 1) != 1) {
+ break;
+ }
+ }
if (FD_ISSET(p, &ibits)) {
pcc = read(p, ptyibuf, BUFSIZ);
if (pcc < 0 && errno == EWOULDBLOCK)
else {
if (pcc <= 0)
break;
- ptyip = ptyibuf;
+ /* Skip past "packet" */
+ pcc--;
+ ptyip = ptyibuf+1;
}
}
+ if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+ netclear(); /* clear buffer back */
+ *nfrontp++ = IAC;
+ *nfrontp++ = DM;
+ neturg = nfrontp-1; /* off by one XXX */
+ ptyibuf[0] = 0;
+ }
while (pcc > 0) {
if ((&netobuf[BUFSIZ] - nfrontp) < 2)
if (c == IAC)
*nfrontp++ = c;
*nfrontp++ = c;
- if (c == '\r') {
+ /* Don't do CR-NUL if we are in binary mode */
+ if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
*nfrontp++ = *ptyip++ & 0377;
pcc--;
case TS_CR:
state = TS_DATA;
+ /* Strip off \n or \0 after a \r */
if ((c == 0) || (c == '\n')) {
break;
}
if (inter > 0)
break;
/*
- * We map \r\n ==> \n, since \r\n says
+ * We now map \r\n ==> \r for pragmatic reasons.
+ * Many client implementations send \r\n when
+ * the user hits the CarriageReturn key.
+ *
+ * We USED to map \r\n ==> \n, since \r\n says
* that we want to be in column 1 of the next
* printable line, and \n is the standard
* unix way of saying that (\r is only good
* if CRMOD is set, which it normally is).
*/
- if ((myopts[TELOPT_BINARY] == OPT_DONT) && c == '\r') {
- if ((ncc > 0) && ('\n' == *netip)) {
- netip++; ncc--;
- c = '\n';
- } else {
- state = TS_CR;
- }
+ if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
+ state = TS_CR;
}
*pfrontp++ = c;
break;
break;
case TS_WILL:
- if (hisopts[c] != OPT_WILL)
+ if (hisopts[c] != OPT_YES)
willoption(c);
state = TS_DATA;
continue;
case TS_WONT:
- if (hisopts[c] != OPT_WONT)
+ if (hisopts[c] != OPT_NO)
wontoption(c);
state = TS_DATA;
continue;
case TS_DO:
- if (myopts[c] != OPT_DO)
+ if (myopts[c] != OPT_YES)
dooption(c);
state = TS_DATA;
continue;
case TS_DONT:
- if (myopts[c] != OPT_DONT) {
+ if (myopts[c] != OPT_NO) {
dontoption(c);
}
state = TS_DATA;
continue;
default:
+ syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
printf("telnetd: panic state=%d\n", state);
exit(1);
}
* (to the terminal) mode, we need to send a "WILL ECHO".
* Kludge upon kludge!
*/
- if (myopts[TELOPT_ECHO] == OPT_DO) {
+ if (myopts[TELOPT_ECHO] == OPT_YES) {
dooption(TELOPT_ECHO);
}
fmt = dont;
break;
case TELOPT_TTYPE:
+ settimer(ttypeopt);
+ if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
+ hisopts[TELOPT_TTYPE] = OPT_YES;
+ return;
+ }
+ fmt = doopt;
+ break;
+
case TELOPT_SGA:
fmt = doopt;
break;
break;
}
if (fmt == doopt) {
- hisopts[option] = OPT_WILL;
+ hisopts[option] = OPT_YES;
} else {
- hisopts[option] = OPT_WONT;
+ hisopts[option] = OPT_NO;
}
- sprintf(nfrontp, fmt, option);
+ (void) sprintf(nfrontp, fmt, option);
nfrontp += sizeof (dont) - 2;
}
case TELOPT_BINARY:
mode(0, RAW);
break;
+
+ case TELOPT_TTYPE:
+ settimer(ttypeopt);
+ break;
}
+
fmt = dont;
- hisopts[option] = OPT_WONT;
- sprintf(nfrontp, fmt, option);
+ hisopts[option] = OPT_NO;
+ (void) sprintf(nfrontp, fmt, option);
nfrontp += sizeof (doopt) - 2;
}
break;
}
if (fmt == will) {
- myopts[option] = OPT_DO;
+ myopts[option] = OPT_YES;
} else {
- myopts[option] = OPT_DONT;
+ myopts[option] = OPT_NO;
}
- sprintf(nfrontp, fmt, option);
+ (void) sprintf(nfrontp, fmt, option);
nfrontp += sizeof (doopt) - 2;
}
switch (option) {
case TELOPT_ECHO: /* we should stop echoing */
- mode(0, ECHO|CRMOD);
+ mode(0, ECHO);
fmt = wont;
break;
+
default:
fmt = wont;
break;
}
+
if (fmt = wont) {
- myopts[option] = OPT_DONT;
+ myopts[option] = OPT_NO;
} else {
- myopts[option] = OPT_DO;
+ myopts[option] = OPT_YES;
}
- sprintf(nfrontp, fmt, option);
+ (void) sprintf(nfrontp, fmt, option);
nfrontp += sizeof (wont) - 2;
}
*
* Currently we recognize:
*
- * (nothing - we only do terminal type at start-up time)
+ * Terminal type is
*/
suboption()
{
- switch (subbuffer[0]&0xff) {
+ switch (SB_GET()) {
+ case TELOPT_TTYPE: { /* Yaaaay! */
+ static char terminalname[5+41] = "TERM=";
+
+ settimer(ttypesubopt);
+
+ if (SB_GET() != TELQUAL_IS) {
+ return; /* ??? XXX but, this is the most robust */
+ }
+
+ terminaltype = terminalname+strlen(terminalname);
+
+ while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
+ !SB_EOF()) {
+ register int c;
+
+ c = SB_GET();
+ if (isupper(c)) {
+ c = tolower(c);
+ }
+ *terminaltype++ = c; /* accumulate name */
+ }
+ *terminaltype = 0;
+ terminaltype = terminalname;
+ break;
+ }
+
default:
;
}
cleanup()
{
-
- rmut();
- vhangup(); /* XXX */
+ char *p;
+
+ p = line + sizeof("/dev/") - 1;
+ if (logout(p))
+ logwtmp(p, "", "");
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ *p = 'p';
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
shutdown(net, 2);
exit(1);
}
-#include <utmp.h>
+char editedhost[32];
-struct utmp wtmp;
-char wtmpf[] = "/usr/adm/wtmp";
-char utmpf[] = "/etc/utmp";
-#define SCPYN(a, b) strncpy(a, b, sizeof(a))
-#define SCMPN(a, b) strncmp(a, b, sizeof(a))
-
-rmut()
+edithost(pat, host)
+ register char *pat;
+ register char *host;
{
- register f;
- int found = 0;
- struct utmp *u, *utmp;
- int nutmp;
- struct stat statbf;
-
- f = open(utmpf, O_RDWR);
- if (f >= 0) {
- fstat(f, &statbf);
- utmp = (struct utmp *)malloc(statbf.st_size);
- if (!utmp)
- syslog(LOG_ERR, "utmp malloc failed");
- if (statbf.st_size && utmp) {
- nutmp = read(f, utmp, statbf.st_size);
- nutmp /= sizeof(struct utmp);
-
- for (u = utmp ; u < &utmp[nutmp] ; u++) {
- if (SCMPN(u->ut_line, line+5) ||
- u->ut_name[0]==0)
- continue;
- lseek(f, ((long)u)-((long)utmp), L_SET);
- SCPYN(u->ut_name, "");
- SCPYN(u->ut_host, "");
- time(&u->ut_time);
- write(f, (char *)u, sizeof(wtmp));
- found++;
- }
+ register char *res = editedhost;
+
+ if (!pat)
+ pat = "";
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+
}
- close(f);
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
}
- if (found) {
- f = open(wtmpf, O_WRONLY|O_APPEND);
- if (f >= 0) {
- SCPYN(wtmp.ut_line, line+5);
- SCPYN(wtmp.ut_name, "");
- SCPYN(wtmp.ut_host, "");
- time(&wtmp.ut_time);
- write(f, (char *)&wtmp, sizeof(wtmp));
- close(f);
+ if (*host)
+ strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static char *putlocation;
+
+puts(s)
+register char *s;
+{
+
+ while (*s)
+ putchr(*s++);
+}
+
+putchr(cc)
+{
+ *putlocation++ = cc;
+}
+
+putf(cp, where)
+register char *cp;
+char *where;
+{
+ char *slash;
+ char datebuffer[60];
+ extern char *rindex();
+
+ putlocation = where;
+
+ while (*cp) {
+ if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+ slash = rindex(line, '/');
+ if (slash == (char *) 0)
+ puts(line);
+ else
+ puts(&slash[1]);
+ break;
+
+ case 'h':
+ puts(editedhost);
+ break;
+
+ case 'd':
+ get_date(datebuffer);
+ puts(datebuffer);
+ break;
+
+ case '%':
+ putchr('%');
+ break;
}
+ cp++;
}
- chmod(line, 0666);
- chown(line, 0, 0);
- line[strlen("/dev/")] = 'p';
- chmod(line, 0666);
- chown(line, 0, 0);
}