|
|
1.1 root 1: /* tp0bridge.c - TCP/X.25 TP0 bridge */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/others/tp0bridge/RCS/tp0bridge.c,v 7.1 90/07/09 14:42:52 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/others/tp0bridge/RCS/tp0bridge.c,v 7.1 90/07/09 14:42:52 mrose Exp $
9: *
10: * Contributed by Julian Onions, Nottingham University in the UK
11: *
12: *
13: * $Log: tp0bridge.c,v $
14: * Revision 7.1 90/07/09 14:42:52 mrose
15: * sync
16: *
17: * Revision 7.0 89/11/23 22:11:02 mrose
18: * Release 6.0
19: *
20: */
21:
22: /*
23: * NOTICE
24: *
25: * Acquisition, use, and distribution of this module and related
26: * materials are subject to the restrictions of a license agreement.
27: * Consult the Preface in the User's Manual for the full terms of
28: * this agreement.
29: *
30: */
31:
32:
33: #include <signal.h>
34: #include <stdio.h>
35: #include <varargs.h>
36: #include "tpkt.h"
37: #include <sys/ioctl.h>
38: #ifdef BSD42
39: #include <sys/file.h>
40: #endif
41: #ifdef SYS5
42: #include <fcntl.h>
43: #endif
44: #include "internet.h"
45: #include "x25.h"
46: #include "logger.h"
47: #include "tailor.h"
48:
49: /* */
50:
51: static int debug = 0;
52: static int options = 0;
53: static int nbits = FD_SETSIZE;
54:
55: static LLog _pgm_log = {
56: "tp0bridge.log", NULLCP, NULLCP,
57: LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, LLOG_FATAL, -1,
58: LLOGCLS | LLOGCRT | LLOGZER, NOTOK
59: };
60: LLog *pgm_log = &_pgm_log;
61:
62: static char *myname = "tp0bridge";
63: static char myhost[64];
64:
65: static char *myprotocol = "tcp";
66: static char *myservice = "x25bridge";
67:
68: static int tcp_fd;
69: static int nfds;
70: static fd_set ifds;
71: static struct sockaddr_in main_in_socket;
72: static struct sockaddr_in *mainisock = &main_in_socket;
73: static struct sockaddr_in emptyaddr;
74:
75: static fd_set sentinel;
76: static int sent2list[FD_SETSIZE];
77: static int list2sent[FD_SETSIZE];
78: static struct sockaddr_in callbacks[FD_SETSIZE];
79: #ifdef CAMTEC
80: static struct NSAPaddr listens[FD_SETSIZE];
81: #define FORK_LISTENER /* new process per listener */
82: #endif
83:
84:
85: void abortfd (), shuffle ();
86: void adios (), advise ();
87: #ifdef BSD42
88: int chldser ();
89: #else
90: int alrmser ();
91: #endif
92:
93:
94: extern int errno;
95:
96: /* */
97:
98: /* ARGSUSED */
99:
100: main (argc, argv, envp)
101: int argc;
102: char **argv,
103: **envp;
104: {
105: int fd;
106: fd_set mask;
107:
108: arginit (argv);
109: envinit ();
110:
111: nfds = 0;
112: FD_ZERO (&ifds);
113: FD_ZERO (&sentinel);
114:
115: if ((tcp_fd = start_tcp_server (mainisock, SOMAXCONN, options & SO_DEBUG
116: ? SO_DEBUG : 0, 0)) == NOTOK)
117: adios ("failed", "start_tcp_server");
118: FD_SET (tcp_fd, &ifds);
119: if (tcp_fd >= nfds)
120: nfds = tcp_fd + 1;
121:
122: #ifdef BSD42
123: (void) signal (SIGCHLD, chldser);
124: #endif
125:
126: for (;;) {
127: mask = ifds;
128:
129: #ifdef CAMTEC
130: /* due to problems in select when camtec is enabled, a small
131: timeout is given. This should not affect anything I hope.
132: */
133: (void) xselect (nfds, &mask, NULLFD, NULLFD, 1);
134: #else
135: (void) xselect (nfds, &mask, NULLFD, NULLFD, NOTOK);
136: #endif
137:
138: for (fd = 0; fd < nbits; fd++)
139: if (FD_ISSET (fd, &mask)) {
140: if (fd == tcp_fd)
141: do_new_fd ();
142: else if (FD_ISSET (fd, &sentinel))
143: abortfd (fd);
144: else
145: do_old_fd (fd);
146: }
147:
148: #ifndef BSD42
149: while (mywait3 (NULLIP) != NOTOK)
150: continue;
151: #endif
152: }
153: }
154:
155: /* */
156:
157: static do_new_fd ()
158: {
159: int fd;
160: char c;
161: struct sockaddr_in zosock;
162: struct sockaddr_in *osock = & zosock;
163:
164: if ((fd = join_tcp_client (tcp_fd, osock)) == NOTOK) {
165: if (errno != EINTR)
166: advise (LLOG_EXCEPTIONS, "failed", "join_tcp_client");
167: return;
168: }
169:
170: if (read_tcp_socket (fd, &c, 1) != 1) {
171: advise (LLOG_EXCEPTIONS, "failed", "initial read_tcp_socket");
172: goto out;
173: }
174:
175: switch (c) {
176: case 1:
177: #ifdef DEBUG
178: advise (LLOG_DEBUG, NULLCP, "outgoing connection");
179: #endif
180: switch (fork ()) {
181: case OK:
182: do_outgoing (fd);
183: _exit (1); /* NOTREACHED */
184:
185: case NOTOK:
186: advise (LLOG_EXCEPTIONS, "TCP socket",
187: "no forks, so rejecting connection on");
188: default:
189: (void) close_tcp_socket (fd);
190: #ifdef EXOS
191: FD_CLR (tcp_fd, &ifds);
192: if ((tcp_fd = start_tcp_server (isock, SOMAXCONN,
193: options & SO_DEBUG ? SO_DEBUG : 0, 0))
194: == NOTOK)
195: adios ("failed", "start_tcp_server");
196: FD_SET (tcp_fd, &ifds);
197: if (tcp_fd >= nfds)
198: nfds = tcp_fd + 1;
199: #endif
200: break;
201: }
202: break;
203:
204: case 2:
205: #ifdef DEBUG
206: advise (LLOG_DEBUG, NULLCP, "setup listen address");
207: #endif
208: do_listen (fd);
209: break;
210:
211: default:
212: advise (LLOG_NOTICE, NULLCP, "unknown dialogue mode 0x%x", c);
213: out: ;
214: (void) close_tcp_socket (fd);
215: break;
216:
217: }
218: }
219:
220: /* */
221:
222: static do_outgoing (fd)
223: int fd;
224: {
225: int sd;
226: struct NSAPaddr znsap;
227: register struct NSAPaddr *nsap = &znsap;
228:
229: #ifdef SOCKETS
230: (void) close_tcp_socket (tcp_fd);
231: #endif
232: for (sd = 0; sd < nbits; sd++)
233: if (sd != fd && FD_ISSET (sd, &ifds))
234: (void) close (sd);
235: #ifdef BSD42
236: (void) signal (SIGCHLD, SIG_DFL);
237: #endif
238:
239: (void) ll_close (pgm_log);
240:
241: if (bridge_read_nsap_addr (fd, nsap, read_tcp_socket) == NOTOK)
242: adios ("failed", "read of NSAP");
243:
244: switch (nsap -> na_stack) {
245: case NA_BRG:
246: nsap -> na_stack = NA_X25; /* we use real X.25 here */
247: break;
248: case NA_X25:
249: break;
250: case NA_NSAP:
251: case NA_TCP:
252: default:
253: adios (NULLCP, "Addressing style not supported (type %d)",
254: nsap -> na_stack);
255: break;
256: }
257:
258: #ifdef DEBUG
259: advise(LLOG_DEBUG, NULLCP, "x25 call on to %*s\n",
260: nsap->na_dtelen, nsap->na_dte);
261: #endif
262: if ((sd = start_x25_client (nsap)) == NOTOK)
263: adios ("failed", "start_x25_client");
264:
265: if (join_x25_server (sd, nsap) == NOTOK)
266: adios ("failed", "join_x25_server");
267:
268: transfer (sd, fd);
269: }
270:
271: /* */
272:
273: static do_listen (fd)
274: int fd;
275: {
276: struct sockaddr_in in_socket;
277: register struct sockaddr_in *isock = &in_socket;
278: struct NSAPaddr znsap;
279: register struct NSAPaddr *nsap = &znsap;
280: int newfd;
281:
282: if (bridge_read_nsap_addr (fd, nsap, read_tcp_socket) == NOTOK) {
283: advise (LLOG_EXCEPTIONS, "failed", "read of NSAP");
284: goto out;
285: }
286: switch (nsap -> na_stack) {
287: case NA_BRG:
288: nsap -> na_stack = NA_X25; /* we use real X.25 here */
289: break;
290: case NA_X25:
291: break;
292: case NA_NSAP:
293: case NA_TCP:
294: default:
295: adios (NULLCP, "Addressing style not supported (type %d)",
296: nsap -> na_stack);
297: break;
298: }
299:
300: #ifdef DEBUG
301: advise (LLOG_DEBUG, NULLCP, "type=%d Listening on '%s' len=%d",
302: nsap -> na_stack, nsap -> na_dte, nsap -> na_dtelen);
303: advise (LLOG_DEBUG, NULLCP, "pid='%s'(%d) fac='%s'(%d) cudf='%s'(%d)",
304: nsap -> na_pid, nsap -> na_pidlen,
305: nsap -> na_fac, nsap -> na_faclen,
306: nsap -> na_pid, nsap -> na_pidlen,
307: nsap -> na_cudf, nsap -> na_cudflen);
308: #endif
309: if (readx (fd, (char *) isock, sizeof *isock, read_tcp_socket)
310: != sizeof *isock) {
311: advise (LLOG_EXCEPTIONS, "failed",
312: "read_tcp_socket of sockaddr_in");
313: goto out;
314: }
315: isock -> sin_family = ntohs (isock -> sin_family);
316:
317: #ifdef FORK_LISTENER
318: switch (fork ()) {
319: case OK:
320: {
321: int i;
322:
323: for (i = 0; i < nbits; i++)
324: if (i != fd && FD_ISSET (i, &ifds))
325: (void) close (i);
326: break;
327: }
328: case NOTOK:
329: advise (LLOG_EXCEPTIONS, "X25 socket",
330: "no forks, so rejecting listen on");
331: default:
332: (void) close_tcp_socket (fd);
333: return;
334: }
335: /* more from the 'stamp out boring names' committee */
336: #define iso_defining_new_protocols 1
337: while (iso_defining_new_protocols)
338: {
339: #endif
340: if ((newfd = start_x25_server (nsap, SOMAXCONN, options & SO_DEBUG
341: ? SO_DEBUG : 0, 0)) == NOTOK) {
342: advise (LLOG_EXCEPTIONS, "failed", "start_x25_server");
343: #ifdef FORK_LISTENER
344: _exit (0);
345: #endif
346: return;
347: }
348: #ifdef CAMTEC
349: listens[newfd] = *nsap; /* struct copy */
350: #endif
351: callbacks[newfd] = *isock; /* struct copy */
352:
353: /* set up the admin stuff */
354: FD_SET (newfd, &ifds); /* listen for new connections */
355: FD_SET (fd, &ifds); /* listen for problems */
356: FD_SET (fd, &sentinel);
357: sent2list[fd] = newfd;
358: list2sent[newfd] = fd;
359: if (newfd >= nfds)
360: nfds = newfd + 1;
361: #ifdef FORK_LISTENER
362: do_old_fd (newfd);
363: (void) close (newfd);
364: } /* loop again */
365: #endif
366: return;
367:
368: out: ;
369: (void) close_tcp_socket (fd);
370: }
371:
372:
373: /* */
374:
375: static do_old_fd (fd)
376: int fd;
377: {
378: int sd;
379: register struct sockaddr_in *isock = &callbacks[fd];
380: struct NSAPaddr znsap;
381: register struct NSAPaddr *nsap = &znsap;
382:
383: #ifdef DEBUG
384: advise (LLOG_DEBUG, NULLCP, "callback");
385: #endif
386: if (isock == NULL || isock -> sin_family != AF_INET) {
387: advise (LLOG_EXCEPTIONS, NULLCP, "Callback has bogus address");
388: return;
389: }
390:
391: if ((sd = join_x25_client (fd, nsap)) == NOTOK) {
392: if (errno != EINTR) {
393: advise (LLOG_EXCEPTIONS, "failed", "join_x25_client");
394: abortfd (list2sent[fd]);
395: }
396: return;
397: }
398: #ifdef DEBUG
399: advise (LLOG_DEBUG, NULLCP, "type=%d Accepted '%s' len=%d",
400: nsap -> na_stack, nsap -> na_dte, nsap -> na_dtelen);
401: advise (LLOG_DEBUG, NULLCP, "pid='%s'(%d) fac='%s'(%d) cudf='%s'(%d)",
402: nsap -> na_pid, nsap -> na_pidlen,
403: nsap -> na_fac, nsap -> na_faclen,
404: nsap -> na_pid, nsap -> na_pidlen,
405: nsap -> na_cudf, nsap -> na_cudflen);
406: #endif
407: nsap -> na_stack = NA_BRG;
408:
409: #ifdef CAMTEC
410: /* get back addressing info for this fd into nsap
411: */
412: nsap = &listens[fd];
413: #endif
414:
415: switch (fork ()) {
416: case OK:
417: break;
418:
419: case NOTOK:
420: advise (LLOG_EXCEPTIONS, "X.25 socket",
421: "no forks, so rejecting connection on");
422: default:
423: (void) close (sd);
424: return;
425: }
426:
427: #ifndef CAMTEC
428: (void) close (fd);
429: #endif
430: for (fd = 0; fd < nbits; fd++)
431: if (fd != sd && FD_ISSET (fd, &ifds))
432: (void) close (fd);
433: #ifdef BSD42
434: (void) signal (SIGCHLD, SIG_DFL);
435: #endif
436:
437: (void) ll_close (pgm_log);
438:
439: #ifdef DEBUG
440: advise (LLOG_DEBUG, NULLCP, "connecting to %s", inet_ntoa (isock -> sin_addr));
441: advise (LLOG_DEBUG, NULLCP, "port=%d", (int) ntohs (isock -> sin_port));
442: #endif
443:
444: if ((fd = start_tcp_client ((struct sockaddr_in *) NULL, 0)) == NOTOK)
445: adios ("failed", "start_tcp_client");
446: if (join_tcp_server (fd, isock) == NOTOK)
447: adios ("failed", "join_tcp_server");
448:
449: if (bridge_write_nsap_addr (fd, nsap, write_tcp_socket) == NOTOK)
450: adios ("failed", "write of NSAP");
451:
452: transfer (sd, fd);
453: _exit (1); /* NOTREACHED */
454: }
455:
456: /* */
457:
458: static transfer (sd, fd)
459: int sd,
460: fd;
461: {
462: int mfds;
463: fd_set rfds,
464: mask;
465: struct tsapblk *tcpb,
466: *x25b;
467:
468: FD_ZERO (&rfds);
469: mfds = (sd > fd ? sd : fd) + 1;
470: FD_SET (sd, &rfds);
471: FD_SET (fd, &rfds);
472:
473: if ((tcpb = newtblk ()) == NULL)
474: adios (NULLCP, "out of memory");
475: tcpb -> tb_fd = fd;
476: (void) TTService (tcpb);
477:
478: if ((x25b = newtblk ()) == NULL)
479: adios (NULLCP, "out of memory");
480: x25b -> tb_fd = sd;
481: (void) XTService (x25b);
482:
483: #ifndef CAMTEC
484: for (;;) {
485: mask = rfds;
486: if (xselect (mfds, &mask, NULLFD, NULLFD, NOTOK) == NOTOK)
487: adios ("failed", "xselect");
488: if (FD_ISSET (sd, &mask))
489: shuffle (x25b, tcpb);
490: if (FD_ISSET (fd, &mask))
491: shuffle (tcpb, x25b);
492: }
493: #else
494: for (;;) {
495: FD_ZERO (&mask);
496: mfds = fd + 1;
497: FD_SET (fd, &mask);
498: if (xselect (mfds, &mask, NULLFD, NULLFD, 1) == NOTOK)
499: adios ("failed", "xselect tcp");
500: if (FD_ISSET (fd, &mask)) {
501: advise (LLOG_DEBUG, NULLCP, "tcp -> x25");
502: shuffle (tcpb, x25b);
503: }
504:
505: FD_ZERO (&mask);
506: mfds = sd + 1;
507: FD_SET (sd, &mask);
508: if (xselect (mfds, &mask, NULLFD, NULLFD, 1) == NOTOK)
509: adios ("failed", "xselect x25");
510: if (FD_ISSET (sd, &mask)) {
511: advise (LLOG_DEBUG, NULLCP, "x25 -> tcp");
512: shuffle (x25b, tcpb);
513: }
514: }
515: #endif
516: }
517:
518: /* */
519:
520: static void shuffle (from, to)
521: register struct tsapblk *from,
522: *to;
523: {
524: register struct udvec *uv;
525: register struct tsapkt *t;
526:
527: if ((t = fd2tpkt (from -> tb_fd, from -> tb_initfnx, from -> tb_readfnx))
528: == NULL || t -> t_errno != OK)
529: adios (NULLCP, "fd2tpkt failed (%d)", t ? t -> t_errno : NOTOK);
530: #ifdef DEBUG
531: advise (LLOG_DEBUG, NULLCP, "read: code=0x%x user len=%d",
532: TPDU_CODE (t), t -> t_qbuf ? t -> t_qbuf -> qb_len : 0);
533: #endif
534:
535: uv = t -> t_udvec;
536: if (t -> t_qbuf) {
537: uv -> uv_base = t -> t_qbuf -> qb_data;
538: uv -> uv_len = t -> t_qbuf -> qb_len;
539: uv++;
540: }
541: uv -> uv_base = NULL;
542:
543: if (tpkt2fd (to -> tb_fd, t, to -> tb_writefnx) == NOTOK)
544: adios (NULLCP, "tpkt2fd failed (%d)", t -> t_errno);
545:
546: freetpkt (t);
547: }
548:
549: static void abortfd (fd)
550: int fd;
551: {
552: int assocfd = sent2list[fd]; /* get fd that is listening on */
553:
554: #ifdef DEBUG
555: advise (LLOG_DEBUG, NULLCP, "Shutdown listen (%d,%d)", fd, assocfd);
556: #endif
557: FD_CLR (fd, &sentinel);
558: FD_CLR (fd, &ifds);
559: FD_CLR (assocfd, &ifds);
560: (void) close_tcp_socket (fd);
561: (void) close_x25_socket (assocfd);
562: sent2list[fd] = -1;
563: list2sent[assocfd] = -1;
564: callbacks[assocfd] = emptyaddr; /* struct copy */
565: }
566:
567: /* */
568:
569: static arginit (vec)
570: char **vec;
571: {
572: int port;
573: register char *ap;
574: struct hostent *hp;
575: struct servent *sp;
576:
577: if (myname = rindex (*vec, '/'))
578: myname++;
579: if (myname == NULL || *myname == NULL)
580: myname = *vec;
581:
582: isodetailor (myname, 0);
583: ll_hdinit (pgm_log, myname);
584:
585: (void) gethostname (myhost, sizeof myhost);
586: if (hp = gethostbyname (myhost))
587: (void) strcpy (myhost, hp -> h_name);
588:
589: if ((sp = getservbyname (myservice, myprotocol)) == NULL)
590: mainisock -> sin_port = x25_bridge_port;
591: else
592: mainisock -> sin_port = sp -> s_port;
593: mainisock -> sin_family = AF_INET;
594: mainisock -> sin_addr.s_addr = INADDR_ANY;
595: if ((nbits = getdtablesize ()) > FD_SETSIZE)
596: nbits = FD_SETSIZE;
597:
598: for (vec++; ap = *vec; vec++) {
599: if (*ap == '-')
600: switch (*++ap) {
601: case 'd':
602: debug++;
603: continue;
604:
605: case 'p':
606: if ((ap = *++vec) == NULL
607: || *ap == '-'
608: || (port = atoi (ap)) <= 0)
609: adios (NULLCP, "usage: %s -p portno", myname);
610: mainisock -> sin_port = htons ((u_short) port);
611: continue;
612:
613: default:
614: adios (NULLCP, "-%s: unknown switch", ap);
615: }
616:
617: adios (NULLCP, "usage: %s [switches]", myname);
618: }
619: }
620:
621: /* */
622:
623: static envinit () {
624: int i,
625: sd;
626:
627: if (debug == 0 && !(debug = isatty (2))) {
628: for (i = 0; i < 5; i++) {
629: switch (fork ()) {
630: case NOTOK:
631: sleep (5);
632: continue;
633:
634: case OK:
635: break;
636:
637: default:
638: _exit (0);
639: }
640: break;
641: }
642:
643: (void) chdir ("/");
644:
645: if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
646: adios ("/dev/null", "unable to read");
647: if (sd != 0)
648: (void) dup2 (sd, 0), (void) close (sd);
649: (void) dup2 (0, 1);
650: (void) dup2 (0, 2);
651:
652: #ifdef SETSID
653: if (setsid () == NOTOK)
654: advise (LLOG_EXCEPTIONS, "failed", "setsid");
655: #endif
656: #ifdef TIOCNOTTY
657: if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
658: (void) ioctl (sd, TIOCNOTTY, NULLCP);
659: (void) close (sd);
660: }
661: #endif
662: }
663: else {
664: options |= SO_DEBUG;
665: ll_dbinit (pgm_log, myname);
666: }
667:
668: #ifndef sun /* damn YP... */
669: for (sd = 3; sd < nbits; sd++)
670: if (pgm_log -> ll_fd != sd)
671: (void) close (sd);
672: #endif
673:
674: (void) signal (SIGPIPE, SIG_IGN);
675:
676: ll_hdinit (pgm_log, myname);
677: advise (LLOG_NOTICE, NULLCP, "starting");
678: #ifdef DEBUG
679: advise (LLOG_DEBUG, NULLCP, "options=0x%x port=%d",
680: options, ntohs (mainisock -> sin_port));
681: #endif
682: }
683:
684: /* Berkeley UNIX: 4.2 */
685:
686: #ifdef BSD42
687:
688: #include <sys/wait.h>
689:
690: /* ARGSUSED */
691:
692: static int chldser (sig, code, sc)
693: int sig;
694: long code;
695: struct sigcontext *sc;
696: {
697: union wait status;
698:
699: while (wait3 (&status, WNOHANG, (struct rusage *) NULL) > 0)
700: continue;
701: }
702:
703: #else
704:
705: /* AT&T UNIX: 5 */
706:
707: #include <setjmp.h>
708:
709: #define WAITSECS ((unsigned) 2)
710:
711:
712: static jmp_buf jmpenv;
713:
714:
715: /* ARGSUSED */
716:
717: static int alrmser (sig)
718: int sig;
719: {
720: (void) signal (SIGALRM, alrmser);
721:
722: longjmp (jmpenv, NOTOK);
723: }
724:
725:
726: static int mywait3 (status)
727: int *status;
728: {
729: int result;
730:
731: switch (setjmp (jmpenv)) {
732: case OK:
733: (void) signal (SIGALRM, alrmser);
734: (void) alarm (WAITSECS);
735: result = wait (status);
736: (void) alarm (0);
737: break;
738:
739: default:
740: result = NOTOK;
741: break;
742: }
743:
744: return result;
745: }
746: #endif
747:
748: /* */
749:
750: static int readx (fd, buffer, n, readfnx)
751: int fd;
752: char *buffer;
753: int n;
754: IFP readfnx;
755: {
756: register int i,
757: cc;
758: register char *bp;
759:
760: for (bp = buffer, i = n; i > 0; bp += cc, i -= cc) {
761: switch (cc = (*readfnx) (fd, bp, i)) {
762: case NOTOK:
763: return (i = bp - buffer) ? i : NOTOK;
764:
765: case OK:
766: break;
767:
768: default:
769: continue;
770: }
771: break;
772: }
773:
774: return (bp - buffer);
775: }
776:
777: /* ERRORS */
778:
779: #ifndef lint
780: void adios (va_alist)
781: va_dcl
782: {
783: va_list ap;
784:
785: va_start (ap);
786:
787: _ll_log (pgm_log, LLOG_FATAL, ap);
788:
789: va_end (ap);
790:
791: _exit (1);
792: }
793: #else
794: /* VARARGS */
795:
796: void adios (what, fmt)
797: char *what,
798: *fmt;
799: {
800: adios (what, fmt);
801: }
802: #endif
803:
804:
805: #ifndef lint
806: void advise (va_alist)
807: va_dcl
808: {
809: int code;
810: va_list ap;
811:
812: va_start (ap);
813:
814: code = va_arg (ap, int);
815:
816: _ll_log (pgm_log, code, ap);
817:
818: va_end (ap);
819: }
820: #else
821: /* VARARGS */
822:
823: void advise (code, what, fmt)
824: char *what,
825: *fmt;
826: int code;
827: {
828: advise (code, what, fmt);
829: }
830: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.