1: #ifndef lint
2: static char RCSid[] = "$Header: gaptelnetd.c,v 2.0 85/11/21 07:23:06 jqj Exp $";
3: #endif
4: /*
5: * server for GAP-style (TransportObject=server,teletype) telnet connections
6: * Note that we support only GAP version 3
7: */
8:
9: /* $Log: gaptelnetd.c,v $
10: * Revision 2.0 85/11/21 07:23:06 jqj
11: * 4.3BSD standard release
12: *
13: * Revision 1.3 85/11/21 06:53:22 jqj
14: * symbolic values for connection type
15: *
16: * Revision 1.2 85/11/08 17:17:13 bill
17: * version on bullwinkle
18: *
19: * Revision 1.3 85/08/05 09:58:00 jqj
20: * fixed for Interlisp -- data from Interlisp appears with dt==0 (wrong!)
21: * also, Interlisp trys to connect to a tty rather than a ttyHost.
22: * increased inactivity timeout to 4 hrs
23: *
24: * Revision 1.2 85/05/23 06:22:18 jqj
25: * *** empty log message ***
26: *
27: * Revision 1.1 85/05/22 09:46:52 jqj
28: * Initial revision
29: */
30: #include <stdio.h>
31: #include <signal.h>
32: #include <sgtty.h>
33: #include <sys/types.h>
34: #include <sys/time.h>
35: #include <sys/uio.h>
36: #include <sys/socket.h>
37: #include <netns/ns.h>
38: #include <netns/idp.h>
39: #include <netns/sp.h>
40: #include <sys/wait.h>
41: #include <xnscourier/realcourierconnection.h>
42: #include "GAP3.h"
43: #include "gapcontrols.h"
44: #include <xnscourier/except.h>
45: #include <errno.h>
46:
47: #define BELL '\07'
48: #define BANNER "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r"
49:
50: int pty, net;
51: extern CourierConnection *_serverConnection;
52: char buf[sizeof(struct sphdr)+SPPMAXDATA];
53: struct sphdr our_sphdr;
54: struct iovec our_iovec[2] = {{((caddr_t)&our_sphdr), sizeof(our_sphdr)}};
55: /*
56: * I/O data buffers, pointers, and counters.
57: */
58: char ptyibuf[512], *ptyip = ptyibuf;
59: char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
60: char *netip = buf;
61: char netobuf[512], *nfrontp = netobuf, *nbackp = netobuf;
62: int pcc, ncc;
63: char line[12];
64: extern char **environ;
65: extern int errno;
66:
67: char *envinit[3];
68: char wsenv[50];
69:
70: /*
71: * session parameters
72: */
73: Cardinal frametimeout; /* 0 or time in seconds to wait */
74:
75:
76: /*
77: * This modified version of the server is necessary since GAP specifies
78: * that the telnet data-transfer session occurs after the RPC to create
79: * it has returned!
80: */
81: Server(skipcount,skippedwords)
82: int skipcount;
83: Unspecified skippedwords[];
84: {
85: Cardinal _procedure;
86: register Unspecified *_buf;
87: LongCardinal programnum;
88: Cardinal versionnum;
89: Cardinal _n;
90:
91: #ifdef DEBUG
92: BUGOUT("Server: %d %d",skipcount,skippedwords);
93: #endif
94: for (;;) {
95: _buf = ReceiveCallMessage(&_procedure, skipcount, skippedwords);
96: DURING switch (_procedure) {
97: case 3:
98: server_GAP3_Delete(_buf);
99: break;
100: case 2:
101: server_GAP3_Create(_buf);
102: net = _serverConnection->fd;
103: gaptelnet(); /* returns on connection close */
104: break;
105: case 0:
106: server_GAP3_Reset(_buf);
107: break;
108: default:
109: NoSuchProcedureValue("GAP", _procedure);
110: break;
111: } HANDLER {
112: Deallocate(_buf);
113: switch (Exception.Code) {
114: case GAP3_serviceNotFound:
115: case GAP3_userNotAuthorized:
116: case GAP3_userNotAuthenticated:
117: case GAP3_serviceTooBusy:
118: case GAP3_terminalAddressInvalid:
119: case GAP3_terminalAddressInUse:
120: case GAP3_controllerDoesNotExist:
121: case GAP3_controllerAlreadyExists:
122: case GAP3_gapCommunicationError:
123: case GAP3_gapNotExported:
124: case GAP3_bugInGAPCode:
125: case GAP3_tooManyGateStreams:
126: case GAP3_inconsistentParams:
127: case GAP3_transmissionMediumUnavailable:
128: case GAP3_dialingHardwareProblem:
129: case GAP3_noDialingHardware:
130: case GAP3_badAddressFormat:
131: case GAP3_mediumConnectFailed:
132: case GAP3_illegalTransport:
133: case GAP3_noCommunicationHardware:
134: case GAP3_unimplemented:
135: _buf = Allocate(0);
136: SendAbortMessage(Exception.Code-ERROR_OFFSET, 0, _buf);
137: break;
138: default:
139: _buf = Allocate(0);
140: SendRejectMessage(unspecifiedError, 0, _buf);
141: break;
142: }
143: } END_HANDLER;
144: Deallocate(_buf);
145: for (;;) {
146: skipcount = LookAheadCallMsg(&programnum, &versionnum,
147: skippedwords);
148: if (skipcount < 0) return(0); /* timed out */
149: if (programnum != 3 || versionnum != 3)
150: ExecCourierProgram(programnum, versionnum,
151: skipcount, skippedwords);
152: } /* loop if can't exec that program */
153: }
154: }
155:
156: void
157: GAP3_Delete(session)
158: GAP3_SessionHandle session;
159: {
160: }
161:
162: void
163: GAP3_Reset()
164: {
165: }
166:
167: GAP3_CreateResults
168: GAP3_Create(conn, BDTproc, sessionparams, transports,
169: createTimeout, credentials, verifier)
170: CourierConnection *conn;
171: int BDTproc;
172: GAP3_SessionParameterObject sessionparams;
173: struct {Cardinal length;
174: GAP3_TransportObject *sequence;
175: } transports;
176: GAP3_WaitTime createTimeout;
177: Authentication1_Credentials credentials;
178: Authentication1_Verifier verifier;
179: {
180: GAP3_CreateResults result;
181: char *c1, *c2, *host;
182: int t, pid;
183: struct sgttyb b;
184: char *xntoa(), *wsname();
185: struct sockaddr_ns who;
186: int whosize = sizeof(who);
187: LongCardinal servicetype;
188: GAP3_CommParamObject *cp;
189: GAP3_Duplexity duplexity; /* fullDuplex, halfDuplex */
190:
191: #ifdef DEBUG
192: BUGOUT("CREATE");
193: #endif
194: switch (sessionparams.designator) {
195: case oldTty:
196: case oldTtyHost:
197: frametimeout = sessionparams.oldTtyHost_case.frameTimeout/1000;
198: /* could set other parameters here */
199: break;
200: case tty:
201: case ttyHost:
202: frametimeout = sessionparams.ttyHost_case.frameTimeout/1000;
203: /* could set other parameters here */
204: break;
205: default:
206: raise(GAP3_unimplemented, 0);
207: /*NOTREACHED*/
208: }
209: if (transports.length != 2) {
210: raise(GAP3_illegalTransport);
211: /*NOTREACHED*/
212: }
213: switch (transports.sequence[0].designator) {
214: case service:
215: servicetype = transports.sequence[0].service_case.id;
216: switch (servicetype) {
217: case TTYService_any: /* 0 */
218: servicetype = TTYService_sa;
219: case TTYService_sa: /* 1 */
220: case TTYService_exec: /* 2 */
221: case TTYService_its: /* 3 */
222: break;
223: default:
224: raise(GAP3_serviceNotFound, 0);
225: /*NOTREACHED*/
226: }
227: duplexity = fullduplex;/* services are allways fulldup */
228: break;
229: case rs232c: /* maybe some day */
230: cp = &transports.sequence[0].rs232c_case.commParams;
231: if (cp->accessDetail.designator == directConn) {
232: duplexity = cp->accessDetail.directConn_case.duplex;
233: servicetype = TTYService_sa; /* fake it */
234: break;
235: }
236: raise(GAP3_noCommunicationHardware, 0);
237: /*NOTREACHED*/
238: default:
239: raise(GAP3_illegalTransport, 0);
240: /*NOTREACHED*/
241: }
242: if (transports.sequence[1].designator != teletype)
243: raise(GAP3_illegalTransport, 0);
244: /* ignore createTimeout */
245: /* ignore credentials and verifier */
246:
247: for (c1 = "pq"; *c1 != 0; c1++)
248: for (c2 = "0123456789abcdef"; *c2 != 0; c2++) {
249: sprintf(line, "/dev/pty%c%c", *c1, *c2);
250: pty = open(line, 2);
251: if (pty < 0) continue;
252: line[strlen("/dev/")] = 't';
253: t = open(line, 2);
254: if (t > 0) goto gotpty;
255: close(pty);
256: }
257: raise(GAP3_serviceTooBusy, 0);
258: /*NOTREACHED*/
259: gotpty:
260: getpeername(_serverConnection->fd, &who, &whosize);
261: host = wsname(who.sns_addr);
262: #ifdef DEBUG
263: BUGOUT("gotpty <%s> %d <%s>",line, pty, host);
264: #endif
265: ioctl(t, TIOCGETP, &b);
266: b.sg_flags = CRMOD|XTABS|ANYP;
267: ioctl(t, TIOCSETP, &b);
268: ioctl(pty, TIOCGETP, &b);
269: if (duplexity == fullduplex)
270: b.sg_flags |= ECHO;
271: else
272: b.sg_flags &= ~ECHO;
273: ioctl(pty, TIOCSETP, &b);
274: /* we do the fork now so we can return failures as REPORTS */
275: pid = fork();
276: if (pid < 0) {
277: close(pty); close(t);
278: raise(GAP3_serviceTooBusy, 0);
279: /*NOTREACHED*/
280: }
281: else if (pid == 0) { /* in the execed fork */
282: sleep(1); /* let parent get ready for us */
283: close(_serverConnection->fd); /* close net */
284: close(pty);
285: dup2(t, 0);
286: dup2(t, 1);
287: dup2(t, 2);
288: if (t > 2) close(t);
289: envinit[0] = "TERM=network";
290: envinit[1] = sprintf(wsenv, "WORKSTATION=%s",
291: xntoa(who.sns_addr));
292: envinit[2] = (char*) 0;
293: #ifdef DEBUG
294: BUGOUT("about to exec /bin/login");
295: #endif
296: execl("/bin/login","login", "-h", host, 0);
297: #ifdef DEBUG
298: BUGOUT("exec of /bin/login failed");
299: #endif
300: perror("/bin/login");
301: exit(1);
302: /*NOTREACHED*/
303: }
304: close(t);
305: #ifdef DEBUG
306: BUGOUT("fork successful");
307: #endif
308: result.session[0] = pid;
309: return(result);
310: }
311:
312: jmp_buf childdiedbuf;
313:
314: /*
315: * Main loop. Select from pty and network, and
316: * hand data to telnet receiver finite state machine.
317: * Returns 0 on orderly shutdown, 1 on abnormal shutdown.
318: */
319: gaptelnet()
320: {
321: int on = 1;
322: char hostname[32];
323: int childdied();
324: int ibits = 0, obits = 0;
325: register int c;
326: struct sphdr *si = (struct sphdr *)buf;
327: static struct timeval timeout = {600,0};
328: int keepalives = 0;
329: int i;
330:
331: #ifdef DEBUG
332: BUGOUT("gaptelnet net=%d,pty=%d",net,pty);
333: #endif
334: if (setjmp(childdiedbuf) != 0)
335: return(0); /* child died */
336: signal(SIGCHLD, childdied);
337: signal(SIGTSTP, SIG_IGN);
338: ioctl(net, FIONBIO, &on);
339: ioctl(pty, FIONBIO, &on);
340:
341:
342: /*
343: * Show banner that getty never gave.
344: */
345: gethostname(hostname, sizeof (hostname));
346: sprintf(nfrontp, BANNER, hostname);
347: nfrontp += strlen(nfrontp);
348: /*
349: * Send status message indicating we're ready to go
350: */
351: changeSPPopts(net, GAPCTLnone, 1);
352: sendoobdata(GAPCTLmediumUp);
353: for (;;) {
354: #ifdef DEBUG
355: BUGOUT("looping in gaptelnet");
356: #endif
357: ibits = obits = 0;
358: /*
359: * Never look for input if there's still
360: * stuff in the corresponding output buffer
361: */
362: if (nfrontp - nbackp || pcc > 0)
363: obits |= (1 << net);
364: else
365: ibits |= (1 << pty);
366: if (pfrontp - pbackp || ncc > 0)
367: obits |= (1 << pty);
368: else
369: ibits |= (1 << net);
370: if (ncc < 0 && pcc < 0)
371: break;
372: timeout.tv_sec = 14400; /* 4 hrs. */
373: timeout.tv_usec = 0;
374: select(16, &ibits, &obits, 0, &timeout);
375: if (ibits == 0 && obits == 0) {
376: /* timeout means no activity for a long time */
377: #ifdef DEBUG
378: BUGOUT("timeout from select");
379: #endif
380: if (keepalives++ < 2) {
381: /* first time through send warning */
382: if (nfrontp == nbackp && pcc == 0) {
383: /* but only if not blocked on output */
384: #define WARNING "\r\nYou've been idle much too long. Respond or log off.\r\n"
385: strcpy(nfrontp, WARNING);
386: nfrontp += sizeof(WARNING);
387: }
388: sleep(5);
389: continue;
390: }
391: #ifdef DEBUG
392: BUGOUT("keepalive expired -- calling cleanup");
393: #endif
394: /* keepalive count has expired */
395: cleanup();
396: return(1);
397: }
398:
399: /*
400: * Something to read from the network...
401: */
402: if (ibits & (1 << net)) {
403: ncc = read(net, buf, sizeof(buf));
404: #ifdef DEBUG
405: BUGOUT("read %d from net, cc=0%o,dt=0%o",
406: ncc-sizeof(struct sphdr), si->sp_cc, si->sp_dt);
407: #endif
408: if (ncc < 0 && errno == EWOULDBLOCK)
409: ncc = 0;
410: else if (ncc < sizeof(struct sphdr)) {
411: #ifdef DEBUG
412: BUGOUT("short read, %d. calling cleanup",ncc);
413: #endif
414: cleanup(); /* will probably fail or block */
415: return(1);
416: }
417: else if (si->sp_cc & SP_OB) {
418: #ifdef DEBUG
419: BUGOUT("Got OOB control 0%o",
420: (u_char) buf[sizeof(struct sphdr)]);
421: #endif
422: /* a status or OOB control */
423: switch ((u_char) buf[sizeof(struct sphdr)]) {
424: case GAPCTLinterrupt:
425: /* shove interrupt char in buffer */
426: interrupt();
427: break; /* from switch */
428: case GAPCTLareYouThere:
429: sendoobdata(GAPCTLiAmHere);
430: break; /* from switch */
431: default:
432: /* Ignore other controls instead of:
433: * sendoobdata(
434: * GAPCTLunexpectedRemoteBehavior);
435: */
436: break; /* from switch */
437: }
438: ncc = 0; /* no chars here */
439: }
440: else if (si->sp_dt==GAPCTLnone ||
441: si->sp_dt==0) {
442: /* the normal case */
443: /* N.B. the standard says dt should be 0300
444: * i.e. GAPCTLnone, but Interlisp CHAT
445: * generates 0, so we accept that too.
446: */
447: ncc -= sizeof(struct sphdr);
448: #ifdef DEBUG
449: BUGOUT("Now ncc == %d",ncc);
450: #endif
451: netip = buf + sizeof(struct sphdr);
452: keepalives = 0;
453: }
454: else if(si->sp_dt==GAPCTLcleanup) {
455: #ifdef DEBUG
456: BUGOUT("got CLEANUP packet. Done");
457: #endif
458: cleanup(); /* normal termination */
459: return(0);
460: }
461: else if (si->sp_dt==SPPSST_END) {
462: /* got premature termination */
463: quitquit(net, pty);
464: return(1);
465: }
466: else {
467: /* some other inband ctl */
468: #ifdef DEBUG
469: BUGOUT("ignoring IB packet, data = 0%o...",
470: (u_char) buf[sizeof(struct sphdr)]);
471: #endif
472: }
473: }
474:
475: /*
476: * Something to read from the pty...
477: */
478: if (ibits & (1 << pty)) {
479: if (frametimeout > 0) sleep(frametimeout);
480: pcc = read(pty, ptyibuf, sizeof(ptyibuf));
481: #ifdef DEBUG
482: BUGOUT("read from pty %d",pcc);
483: #endif
484: if (pcc < 0 && errno == EWOULDBLOCK)
485: pcc = 0;
486: else if (pcc <= 0) {
487: #ifdef DEBUG
488: BUGOUT("short read from pty. Calling cleanup");
489: #endif
490: cleanup();
491: return(1); /* ?? abnormal termination */
492: }
493: ptyip = ptyibuf;
494: }
495:
496: while (pcc > 0) {
497: if ((&netobuf[sizeof(netobuf)] - nfrontp) < 2)
498: break;
499: *nfrontp++ = *ptyip++ & 0377; pcc--;
500: }
501: if ((obits & (1 << net)) && (nfrontp - nbackp) > 0)
502: netflush();
503: while (ncc > 0) {
504: if ((&ptyobuf[sizeof(ptyobuf)] - pfrontp) < 2) break;
505: *pfrontp++ = *netip++ & 0377;
506: ncc--;
507: }
508: if ((obits & (1 << pty)) && (pfrontp - pbackp) > 0)
509: ptyflush();
510: }
511: /* we should never get to here */
512: #ifdef DEBUG
513: BUGOUT("broke out of for(;;) somehow. calling cleanup");
514: #endif
515: cleanup();
516: return(0);
517: }
518:
519: /*
520: * Send out of band data to other end of network
521: */
522: sendoobdata(value)
523: u_char value;
524: {
525: struct {
526: struct sphdr hdr;
527: char val;
528: } oob;
529: oob.hdr = our_sphdr;
530: oob.val = value;
531: #ifdef DEBUG
532: BUGOUT("sendoobdata 0%o",value);
533: #endif
534: send(net, &oob, sizeof(oob), MSG_OOB);
535: }
536:
537: /*
538: * Send interrupt to process on other side of pty.
539: * If it is in raw mode, just write NULL;
540: * otherwise, write intr char.
541: */
542: interrupt()
543: {
544: struct sgttyb b;
545: struct tchars tchars;
546:
547: ptyflush(); /* half-hearted */
548: ioctl(pty, TIOCGETP, &b);
549: if (b.sg_flags & RAW) {
550: *pfrontp++ = '\0';
551: return;
552: }
553: *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
554: '\177' : tchars.t_intrc;
555: }
556:
557: ptyflush()
558: {
559: register int n;
560:
561: if ((n = pfrontp - pbackp) > 0)
562: n = write(pty, pbackp, n);
563: #ifdef DEBUG
564: BUGOUT("ptyflush wrote %d",n);
565: #endif
566: if (n < 0)
567: return;
568: pbackp += n;
569: if (pbackp >= pfrontp) /* actually, > is an error */
570: pbackp = pfrontp = ptyobuf;
571: }
572:
573: netflush()
574: {
575: register int n;
576:
577: if ((n = nfrontp - nbackp) > 0) {
578: our_iovec[1].iov_len = ((n > SPPMAXDATA) ? SPPMAXDATA : n);
579: our_iovec[1].iov_base = nbackp;
580: n = writev(net, our_iovec, 2) - sizeof(struct sphdr);
581: }
582: #ifdef DEBUG
583: BUGOUT("netflush wrote %d",n);
584: if (our_iovec[0].iov_base != (char*)&our_sphdr)
585: BUGOUT("Oops: our_iovec clobbered");
586: BUGOUT("header: %d %d, %d %d %d %d %d %d",
587: our_sphdr.sp_cc, our_sphdr.sp_dt,
588: our_sphdr.sp_sid, our_sphdr.sp_did, our_sphdr.sp_seq,
589: our_sphdr.sp_ack, our_sphdr.sp_alo);
590: #endif
591: if (n < 0) {
592: if (errno == EWOULDBLOCK)
593: return;
594: /* should blow this guy away... */
595: return;
596: }
597: nbackp += n;
598: if (nbackp >= nfrontp) /* actually , > is an error */
599: nbackp = nfrontp = netobuf;
600: }
601:
602: /*
603: * handle receipt of an SPPSST_END packet
604: * This is currently an error, since client didn't send "cleanup" first
605: */
606: quitquit()
607: {
608: #ifdef DEBUG
609: BUGOUT("quitquit");
610: #endif
611: changeSPPopts(net, SPPSST_ENDREPLY, 1);
612: write(net, &our_sphdr, sizeof(our_sphdr));
613: sleep(3);
614:
615: rmut();
616: vhangup(); /* XXX */
617: shutdown(net, 1);
618: close(net);
619: }
620:
621: /*
622: * shut down the data connection for one reason or another
623: */
624: cleanup()
625: {
626: int fdmask;
627: struct timeval timeout;
628: struct sphdr *si = (struct sphdr *)buf;
629: int off = 0;
630:
631: signal(SIGCHLD, SIG_IGN);
632: sendoobdata(GAPCTLcleanup);
633: changeSPPopts(net, SPPSST_END, 1);
634: if (write(net, &our_sphdr, sizeof(our_sphdr)) < 0) {
635: fdmask = 1<<net;
636: timeout.tv_sec = 10;
637: while (select(net+1,&fdmask,(int*)0, (int*)0, &timeout) > 0 &&
638: read(net,buf,sizeof(buf)) >= sizeof(struct sphdr)) {
639: #ifdef DEBUG
640: BUGOUT("cleanup -- got packet");
641: #endif
642: if ((!(si->sp_cc & SP_OB))
643: && si->sp_dt == SPPSST_ENDREPLY) {
644: changeSPPopts(net, SPPSST_ENDREPLY, 1);
645: write(net, &our_sphdr, sizeof(our_sphdr));
646: #ifdef DEBUG
647: BUGOUT("cleanup -- wrote ENDREPLY");
648: #endif
649: sleep(1);
650: changeSPPopts(net,0,0);
651: ioctl(net, FIONBIO, &off);
652: rmut();
653: vhangup(); /* XXX */
654: return;
655: }
656: /* loop: ignore everything except ENDREPLY */
657: fdmask = 1<<net;
658: timeout.tv_sec = 10;
659: }
660: /* timed out or read failed */
661: changeSPPopts(net, SPPSST_ENDREPLY, 1);
662: write(net, &our_sphdr, sizeof(our_sphdr));
663: sleep(1);
664: }
665: shutdown(net, 1);
666: close(net);
667: rmut();
668: vhangup(); /* XXX */
669: }
670:
671: /*
672: * SIGCHLD interrupt handler
673: */
674: childdied()
675: {
676: #ifdef DEBUG
677: BUGOUT("child died");
678: #endif
679: cleanup();
680: longjmp(childdiedbuf, -1);
681: }
682:
683: changeSPPopts(s, stream, eom)
684: int s; /* SPP socket */
685: u_char stream; /* datastream type */
686: char eom; /* Boolean EOM */
687: {
688: our_sphdr.sp_dt = stream;
689: our_sphdr.sp_cc = (eom ? SP_EM : 0);
690: }
691:
692:
693: #include <utmp.h>
694:
695: struct utmp wtmp;
696: char wtmpf[] = "/usr/adm/wtmp";
697: char utmp[] = "/etc/utmp";
698: #define SCPYN(a, b) strncpy(a, b, sizeof (a))
699: #define SCMPN(a, b) strncmp(a, b, sizeof (a))
700:
701: rmut()
702: {
703: register f;
704: int found = 0;
705:
706: f = open(utmp, 2);
707: if (f >= 0) {
708: while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
709: if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
710: continue;
711: lseek(f, -(long)sizeof (wtmp), 1);
712: SCPYN(wtmp.ut_name, "");
713: SCPYN(wtmp.ut_host, "");
714: time(&wtmp.ut_time);
715: write(f, (char *)&wtmp, sizeof (wtmp));
716: found++;
717: }
718: close(f);
719: }
720: if (found) {
721: f = open(wtmpf, 1);
722: if (f >= 0) {
723: SCPYN(wtmp.ut_line, line+5);
724: SCPYN(wtmp.ut_name, "");
725: SCPYN(wtmp.ut_host, "");
726: time(&wtmp.ut_time);
727: lseek(f, (long)0, 2);
728: write(f, (char *)&wtmp, sizeof (wtmp));
729: close(f);
730: }
731: }
732: chmod(line, 0666);
733: chown(line, 0, 0);
734: line[strlen("/dev/")] = 'p';
735: chmod(line, 0666);
736: chown(line, 0, 0);
737: }
738:
739: /*
740: * Convert network-format xns address
741: * to ascii
742: * --Replace this with a clearinghouse name lookup someday.
743: */
744: char *
745: wsname(addr)
746: struct ns_addr addr;
747: {
748: static char b[50];
749: char temp[10];
750: int i;
751:
752: /* net */
753: sprintf(b, "%D.", ntohl(ns_netof(addr)));
754: /* skip leading zeros */
755: for(i=0; (addr.x_host.c_host[i] == (char) 0); i++) ;
756: /* print the rest */
757: for(; i < 6; i++) {
758: sprintf(temp,"%x", addr.x_host.c_host[i]);
759: strcat(b, temp);
760: if(i != 5) strcat(b, ":");
761: }
762: return (b);
763: }
764:
765: /*
766: * generate an xns address that "DE" can parse.
767: * This goes in the environment. Should be the same as above
768: */
769: char *
770: xntoa(addr)
771: struct ns_addr addr;
772: {
773: static char b[50];
774: char temp[10];
775: int i;
776:
777: /* net */
778: sprintf(b, "%X#", ntohl(ns_netof(addr)));
779: /* print the rest */
780: for(i=0; i < 6; i++) {
781: sprintf(temp,"%x", addr.x_host.c_host[i]);
782: strcat(b, temp);
783: if(i != 5) strcat(b, ".");
784: }
785: return (b);
786: }
787:
788: #ifdef DEBUG
789: BUGOUT(str,a,b,c,d,e,f,g,h)
790: char *str;
791: {
792: FILE *fd;
793: fd = fopen("/tmp/GAP3d.log","a");
794: fprintf(fd,str,a,b,c,d,e,f,g,h);
795: putc('\n',fd);
796: fclose(fd);
797: }
798: #endif