|
|
1.1 root 1: /* tsbridge.c: transport bridge - jpo version ! */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/others/tsbridge/RCS/tsbridge.c,v 7.5 90/07/09 14:43:01 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/others/tsbridge/RCS/tsbridge.c,v 7.5 90/07/09 14:43:01 mrose Exp $
9: *
10: * Contributed by Julian Onions, Nottingham University in the UK
11: *
12: *
13: * $Log: tsbridge.c,v $
14: * Revision 7.5 90/07/09 14:43:01 mrose
15: * sync
16: *
17: * Revision 7.4 90/03/19 14:27:00 mrose
18: * jpo
19: *
20: * Revision 7.2 90/01/11 18:36:55 mrose
21: * real-sync
22: *
23: * Revision 7.1 89/11/27 05:43:28 mrose
24: * sync
25: *
26: * Revision 7.0 89/11/23 22:11:12 mrose
27: * Release 6.0
28: *
29: */
30:
31: /*
32: * NOTICE
33: *
34: * Acquisition, use, and distribution of this module and related
35: * materials are subject to the restrictions of a license agreement.
36: * Consult the Preface in the User's Manual for the full terms of
37: * this agreement.
38: *
39: */
40:
41:
42: #include <signal.h>
43: #include <stdio.h>
44: #include <varargs.h>
45: #include "manifest.h"
46: #include <sys/ioctl.h>
47: #ifdef BSD42
48: #include <sys/file.h>
49: #endif
50: #ifdef SYS5
51: #include <fcntl.h>
52: #endif
53: #include "tsap.h"
54: #include "logger.h"
55: #include "psap.h"
56: #include "tailor.h"
57:
58: /* */
59:
60: static int debug = 0;
61: static int nbits = FD_SETSIZE;
62:
63: static LLog _pgm_log = {
64: "tsbridge.log", NULLCP, NULLCP,
65: LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, LLOG_FATAL,
66: -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK
67: };
68:
69: LLog *pgm_log = &_pgm_log;
70:
71: static char *myname = "tsbridge";
72:
73: typedef struct ContTbl {
74: struct TSAPaddr src;
75: struct TSAPaddr dest;
76: unsigned int flags;
77: #define CONN_STRICT 01
78: #define CONN_TRANS 02
79: #define CONN_NOMUNGE 04
80: #define CONN_FORCEMUNGE 010
81: } ContTbl;
82: ContTbl con_tbl[FD_SETSIZE];
83: int con_tbl_cnt = 0;
84:
85: static struct TSAPaddr *maketa ();
86: static struct TSAPaddr *getnewta ();
87: static ContTbl *find_connection ();
88:
89: static void read_file ();
90:
91: static void adios (), advise ();
92:
93: static void ts_adios (), ts_advise ();
94: static void ts_close (), ts_discon ();
95: static void tsbridge (), do_the_biz (), copy_tsdu (), arginit (), envinit ();
96: /* */
97:
98: /* ARGSUSED */
99:
100: main (argc, argv, envp)
101: int argc;
102: char **argv,
103: **envp;
104: {
105: struct TSAPdisconnect tds;
106: register struct TSAPdisconnect *td = &tds;
107: struct TSAPaddr tas, *ta = &tas;
108: int vecp;
109: char *vec[4];
110:
111: arginit (argv);
112:
113: envinit ();
114:
115: for (vecp = 0; vecp < con_tbl_cnt; vecp++) {
116: advise (LLOG_TRACE, NULLCP, "Listening on %s",
117: taddr2str (&con_tbl[vecp].src));
118: if (TNetListen (&con_tbl[vecp].src, td) == NOTOK) {
119: advise (LLOG_FATAL, NULLCP, "Listen failed on \"%s\"",
120: taddr2str (&con_tbl[vecp].src));
121: ts_adios (td, "listen failed");
122: }
123: }
124:
125: for (;;) {
126: if (TNetAcceptAux (&vecp, vec, NULLIP, ta, 0, NULLFD, NULLFD,
127: NULLFD, NOTOK, td) == NOTOK)
128: ts_adios (td, "accept failed");
129:
130: if (vecp <= 0)
131: continue;
132:
133: advise (LLOG_TRACE, NULLCP, "accepted new connection");
134: switch (TNetFork (vecp, vec, td)) {
135: case OK:
136: tsbridge (vecp, vec, ta);
137: exit (1);
138: /* NOTREACHED */
139:
140: case NOTOK:
141: ts_advise (td, LLOG_EXCEPTIONS, "fork failed");
142: break;
143:
144: default:
145: break;
146: }
147: }
148: }
149:
150: /* */
151:
152: static void tsbridge (vecp, vec, ta)
153: int vecp;
154: char **vec;
155: struct TSAPaddr *ta;
156: {
157: struct TSAPstart tss;
158: register struct TSAPstart *ts = &tss;
159: struct TSAPdisconnect tds;
160: register struct TSAPdisconnect *td = &tds;
161: struct TSAPaddr *tota;
162: struct TSAPaddr *fromta;
163: struct TSAPconnect tcs;
164: struct TSAPconnect *tc = &tcs;
165: int sd;
166: ContTbl *ctp;
167:
168: if (TInit (vecp, vec, ts, td) == NOTOK)
169: ts_adios (td, "T-CONNECT.INDICATION failed");
170:
171: sd = ts -> ts_sd;
172: advise (LLOG_NOTICE, NULLCP,
173: "T-CONNECT.INDICATION: <%d, %s, %s, %d, %d>",
174: ts -> ts_sd, taddr2str (&ts -> ts_calling),
175: taddr2str (&ts -> ts_called),
176: ts -> ts_expedited, ts -> ts_tsdusize);
177:
178: ctp = find_connection (ta);
179: if (ctp == NULL) {
180: ts_close (sd, "Unknown listener address");
181: exit (1);
182: }
183: advise (LLOG_TRACE, NULLCP, "Accepted from address %s",
184: taddr2str (&ctp -> src));
185:
186: tota = getnewta (&ts -> ts_called, sd, ctp);
187:
188: fromta = maketa (&ts -> ts_calling, tota -> ta_addrs[0].na_stack, ctp);
189:
190: if ((ctp -> flags & CONN_TRANS) == 0) {
191: ts -> ts_expedited = 0;
192: if (ts -> ts_cc > 0) {
193: advise (LLOG_EXCEPTIONS, NULLCP,
194: "%d octets initial user-data",
195: ts -> ts_cc);
196: ts_close (sd, "initial user-data not allowed");
197: exit (1);
198: }
199: }
200:
201: advise (LLOG_NOTICE, NULLCP,
202: "T-CONNECT.REQUEST: <%s, %s, %d, 0x%x/%d>",
203: taddr2str (fromta), taddr2str (tota), ts -> ts_expedited,
204: ts -> ts_data, ts -> ts_cc);
205:
206: if (TConnRequest (fromta, tota, ts -> ts_expedited,
207: ts -> ts_data, ts -> ts_cc, &ts -> ts_qos,
208: tc, td) == NOTOK) {
209: ts_close (sd, "connection establishment failed");
210: ts_adios(td, "T-CONNECT.REQUEST");
211: }
212: if (TConnResponse (sd, &tc -> tc_responding,
213: tc -> tc_expedited, tc -> tc_data, tc -> tc_cc,
214: &tc -> tc_qos, td) == NOTOK) {
215: ts_close (sd, "connection establishment failed");
216: ts_close (tc -> tc_sd, "connection establishment failed");
217: ts_adios (td, "T-CONNECT.RESPONSE");
218: }
219:
220: do_the_biz (sd, tc -> tc_sd);
221: }
222:
223: /* */
224:
225: static void do_the_biz (sd1, sd2)
226: int sd1, sd2;
227: {
228: int nfds = 0;
229: fd_set rmask, imask;
230: struct TSAPdisconnect tds;
231: register struct TSAPdisconnect *td = &tds;
232:
233: FD_ZERO (&rmask);
234:
235: if (TSelectMask (sd1, &rmask, &nfds, td) == NOTOK
236: || TSelectMask (sd2, &rmask, &nfds, td) == NOTOK)
237: ts_adios (td, "TSelectMask failed");
238:
239: for (;;) {
240: imask = rmask;
241: if (xselect (nfds, &imask, NULLFD, NULLFD, NOTOK) == NOTOK)
242: adios ("select", "failed");
243:
244: if (FD_ISSET (sd1, &imask))
245: copy_tsdu (sd1, sd2);
246: if (FD_ISSET (sd2, &imask))
247: copy_tsdu (sd2, sd1);
248: }
249: }
250:
251: /* */
252:
253: static void copy_tsdu (s1, s2)
254: int s1, s2;
255: {
256: struct TSAPdisconnect tds;
257: register struct TSAPdisconnect *td = &tds;
258: struct TSAPdata txs;
259: register struct TSAPdata *tx = &txs;
260: int result;
261: char *p;
262:
263: SLOG (pgm_log, LLOG_DEBUG, NULLCP, ("copy_tsdu (%d -> %d)", s1, s2));
264:
265: if (TReadRequest (s1, tx, OK, td) == NOTOK) {
266: switch (td -> td_reason) {
267: case DR_TIMER:
268: case DR_WAITING:
269: case DR_OPERATION:
270: case DR_PARAMETER:
271: ts_advise (td, LLOG_TRACE, "TReadRequest");
272: return;
273:
274: case DR_NORMAL:
275: ts_discon (td, s2);
276: break;
277:
278: default:
279: ts_adios (td, "TReadRequest");
280: }
281: }
282:
283: if (tx -> tx_expedited) {
284: SLOG (pgm_log, LLOG_DEBUG, NULLCP, ("TExpdRequest"));
285: p = qb2str (&tx -> tx_qbuf);
286: result = TExpdRequest (s2, p, tx -> tx_cc, td);
287: free (p);
288: }
289: else {
290: struct qbuf *qb;
291: int uiocnt = 0;
292: struct udvec uvec[100];
293: int total;
294:
295: total = uiocnt = 0;
296: for (qb = tx-> tx_qbuf.qb_forw; qb != &tx -> tx_qbuf;
297: qb = qb -> qb_forw) {
298: uvec[uiocnt].uv_base = qb -> qb_data;
299: uvec[uiocnt++].uv_len = qb -> qb_len;
300: total += qb -> qb_len;
301: if (uiocnt > 100)
302: adios (NULLCP, "Internal buffer overflow");
303: }
304: uvec[uiocnt].uv_base = NULLCP;
305: uvec[uiocnt].uv_len = 0;
306: if (tx -> tx_cc != total)
307: advise (NULLCP, LLOG_EXCEPTIONS,
308: "Mismatch in data %d != %d",
309: tx -> tx_cc, total);
310: SLOG (pgm_log, LLOG_DEBUG, NULLCP, ("TWriteRequest"));
311: result = TWriteRequest (s2, uvec, td);
312: }
313: TXFREE (tx);
314:
315: if (result == NOTOK) {
316: if (td -> td_reason == DR_NORMAL)
317: ts_discon (td, s1);
318:
319: ts_adios (td, tx -> tx_expedited ? "T-EXPEDITED-DATA.REQUEST"
320: : "T-DATA.REQUEST");
321: }
322: }
323:
324: /* */
325:
326: static void ts_discon (td, sd)
327: struct TSAPdisconnect *td;
328: int sd;
329: {
330: ts_close (sd, "Normal Disconnect");
331: ts_advise (td, LLOG_NOTICE, "T-DISCONNECT.INDICATION");
332:
333: exit (0);
334: }
335:
336: /* */
337:
338: static void ts_close (sd, event)
339: int sd;
340: char *event;
341: {
342: struct TSAPdisconnect tds;
343: register struct TSAPdisconnect *td = &tds;
344:
345: if (strlen (event) >= TD_SIZE)
346: event = NULLCP;
347: if (TDiscRequest (sd, event, event ? strlen (event) + 1: 0, td)
348: == NOTOK)
349: ts_advise (td, LLOG_EXCEPTIONS, "T-DISCONNECT.REQUEST");
350: }
351:
352: /* */
353:
354: static void ts_adios (td, event)
355: register struct TSAPdisconnect *td;
356: char *event;
357: {
358: ts_advise (td, LLOG_EXCEPTIONS, event);
359:
360: exit (1);
361: }
362:
363: /* */
364:
365: static void ts_advise (td, code, event)
366: register struct TSAPdisconnect *td;
367: int code;
368: char *event;
369: {
370: char buffer[BUFSIZ];
371:
372: if (td -> td_cc > 0)
373: (void) sprintf (buffer, "[%s] %*.*s",
374: TErrString (td -> td_reason),
375: td -> td_cc, td -> td_cc, td -> td_data);
376: else
377: (void) sprintf (buffer, "[%s]", TErrString (td -> td_reason));
378:
379: advise (code, NULLCP, "%s: %s", event, buffer);
380: }
381:
382: /* */
383:
384: static struct TSAPaddr *getnewta (ta, sd, ctp)
385: struct TSAPaddr *ta;
386: int sd;
387: ContTbl *ctp;
388: {
389: static struct TSAPaddr newta;
390: struct TSAPaddr *nta = &newta;
391: char buffer[TSSIZE + 1];
392:
393: if (ctp -> flags & CONN_TRANS) { /* make transparent address */
394: *nta = ctp -> dest; /* struct copy */
395: nta -> ta_selectlen = ta -> ta_selectlen;
396: bcopy (ta -> ta_selector, nta -> ta_selector,
397: ta -> ta_selectlen);
398: return nta;
399: }
400:
401: /* do the real TS bridge stuff */
402: if (ta -> ta_selectlen == 0) {
403: ts_close (sd, "no transport selector");
404: adios (NULLCP, "no transport selector");
405: }
406:
407: bcopy (ta -> ta_selector, buffer, ta -> ta_selectlen);
408: buffer[ta -> ta_selectlen] = NULL;
409:
410: if ((nta = str2taddr (buffer)) == NULLTA) {
411: ts_close (sd, "unable to translate address");
412: adios (NULLCP, "unable to translate \"%s\"", buffer);
413: }
414: newta = *nta;
415:
416: return &newta;
417: }
418:
419: /* */
420:
421: static struct TSAPaddr *maketa (ta, type, ctp)
422: struct TSAPaddr *ta;
423: long type;
424: ContTbl *ctp;
425: {
426: static struct TSAPaddr newta;
427: register struct TSAPaddr *nta = &newta;
428: char *p;
429: int i;
430: struct PSAPaddr pas;
431: struct PSAPaddr *pa = &pas;
432:
433: if (ctp -> flags & CONN_NOMUNGE) {
434: *nta = *ta; /* struct copy */
435: }
436: if (!(ctp -> flags & CONN_NOMUNGE) || (ctp -> flags & CONN_FORCEMUNGE)) {
437: bzero ((char *)pa, sizeof *pa);
438: pa -> pa_addr.sa_addr = *ta;
439: if ((p = _paddr2str (pa, NULLNA, -1)) == NULL) {
440: if (ctp -> flags & CONN_STRICT)
441: adios (NULLCP, "unable to convert address to text");
442: advise (LLOG_NOTICE, NULLCP,
443: "unable to convert address to text");
444: return ta; /* this may work... */
445: }
446: else {
447: if ((nta -> ta_selectlen = strlen (p)) >= TSSIZE) {
448: if (ctp -> flags & CONN_STRICT)
449: adios (NULLCP, "new selector \"%s\" is too big",
450: p);
451:
452: advise (LLOG_NOTICE, NULLCP,
453: "new selector \"%s\" is too big", p);
454: return ta;
455: }
456: else
457: bcopy (p, nta -> ta_selector, TSSIZE);
458: }
459: }
460: for (i = 0; i < ctp -> src.ta_naddr; i++) {
461: if (ctp -> src.ta_addrs[i].na_stack == type) {
462: /* our address */
463: nta -> ta_addrs[0] = ctp->src.ta_addrs[i];
464: nta -> ta_naddr = 1;
465: return nta;
466: }
467: }
468: /*
469: * This requires an explanation:
470: * If NOMUNGE && FORCEMUNGE we have a semi-transparent bridge
471: * and since [at least on my machine] the recipient of a "transparent"
472: * call sees it as coming from the bridge host, ie the effect is that
473: * of a strict call, the structure that is now in nta, viz:
474: * "calling address"/calling address
475: * is going to get clobbered and appear at the final host as originating
476: * "calling address"/bridge host
477: * anyway. This is what I want.
478: * => return nta
479: */
480: if ((ctp -> flags & CONN_NOMUNGE)
481: && (ctp -> flags & CONN_FORCEMUNGE)
482: && !(ctp -> flags & CONN_STRICT)) {
483: return nta;
484: }
485: if (ctp -> flags & CONN_STRICT)
486: adios (NULLCP, "not listening on this network (%d)", type);
487:
488: advise (LLOG_NOTICE, NULLCP,
489: "not listening on this network (%d)", type);
490:
491: return ta;
492: }
493:
494: /* */
495:
496: static ContTbl *find_connection (ta)
497: struct TSAPaddr *ta;
498: {
499: ContTbl *ctp;
500: struct NSAPaddr *na1, *na2;
501:
502: for (ctp = con_tbl; ctp < &con_tbl[con_tbl_cnt]; ctp ++) {
503: for (na1 = &ctp -> src.ta_addrs[0];
504: na1 < &ctp -> src.ta_addrs[ctp->src.ta_naddr]; na1++) {
505: for (na2 = &ta -> ta_addrs[0];
506: na2 < &ta -> ta_addrs[ta->ta_naddr]; na2 ++) {
507: if (na1 -> na_stack != na2 -> na_stack)
508: continue;
509:
510: switch (na1 -> na_stack) {
511: case NA_NSAP:
512: if (na1 -> na_addrlen == na2 -> na_addrlen &&
513: bcmp (na1 -> na_address, na2 -> na_address,
514: na1 -> na_addrlen) == 0)
515: return ctp;
516: break;
517:
518: case NA_TCP:
519: if (na1 -> na_port == na2 -> na_port &&
520: strcmp (na1 -> na_domain, na2 -> na_domain) == 0)
521: return ctp;
522: break;
523:
524: case NA_X25:
525: case NA_BRG:
526: if (na1 -> na_dtelen == na2 -> na_dtelen &&
527: bcmp (na1 -> na_dte, na2 -> na_dte,
528: na1 -> na_dtelen) == 0 &&
529: na1 -> na_pidlen == na2 -> na_pidlen &&
530: bcmp (na1 -> na_pid, na2 -> na_pid,
531: na1 -> na_pidlen) == 0)
532: return ctp;
533: break;
534: }
535: }
536: }
537: }
538: return NULL;
539: }
540:
541: /* */
542:
543: static void arginit (vec)
544: char **vec;
545: {
546: register char *ap;
547: register struct TSAPaddr *ta;
548:
549: if (myname = rindex (*vec, '/'))
550: myname++;
551: if (myname == NULL || *myname == NULL)
552: myname = *vec;
553:
554: for (vec++; ap = *vec; vec++) {
555: if (*ap == '-' && ap[1])
556: switch (*++ap) {
557: case 'T':
558: if ((ap = *++vec) == NULL || *ap == '-')
559: adios (NULLCP, "usage: %s -T tailorfile", myname);
560: (void) isodesetailor (ap);
561: isodetailor (myname, 0);
562: ll_hdinit (pgm_log, myname);
563: continue;
564:
565: case 'a':
566: if ((ap = *++vec) == NULL || *ap == '-')
567: adios (NULLCP, "usage: %s -a address", myname);
568: if ((ta = str2taddr (ap)) == NULLTA)
569: adios (NULLCP, "bad address \"%s\"", ap);
570: con_tbl[0].src = *ta; /* struct copy */
571: con_tbl[0].flags = 0;
572: con_tbl_cnt = 1;
573: continue;
574:
575: case 's':
576: con_tbl[0].flags |= CONN_STRICT;
577: continue;
578:
579: default:
580: adios (NULLCP, "unknown switch -%s", ap);
581: }
582: else
583: break;
584:
585: }
586: isodetailor (myname, 0);
587: ll_hdinit (pgm_log, myname);
588:
589: for (; ap = *vec; vec++)
590: read_file (ap);
591:
592: if (con_tbl_cnt <= 0) {
593: if ((ta = str2taddr (tsb_default_address)) == NULLTA)
594: adios (NULLCP, "bad default address \"%s\"",
595: tsb_default_address);
596: con_tbl[0].src = *ta; /* struct copy */
597: con_tbl_cnt = 1;
598: }
599: }
600:
601: /* */
602:
603: static void read_file (file)
604: char *file;
605: {
606: FILE *fp;
607: char buf[BUFSIZ];
608: char *vec[50];
609: char *ap;
610: int vecp, i;
611: ContTbl *ctp;
612: struct TSAPaddr *ta;
613:
614: if (strcmp (file, "-") == 0)
615: fp = stdin;
616: else if ((fp = fopen (file, "r")) == NULL)
617: adios (file, "Can't open ");
618:
619: while (fgets (buf, sizeof buf, fp) != NULLCP) {
620: if (buf[0] == '#' || buf[0] == '\n')
621: continue;
622:
623: vecp = sstr2arg (buf, 50, vec, " \t,\n");
624: if (vecp <= 0)
625: continue;
626:
627: if ((ta = str2taddr (vec[0])) == NULLTA)
628: adios (NULLCP, "Bad address \"%s\" in file %s", vec[0], file);
629:
630: ctp = &con_tbl[con_tbl_cnt];
631: ctp -> src = *ta; /* struct copy */
632: con_tbl_cnt ++;
633:
634: for (i = 1; i < vecp; i++) {
635: ap = vec[i];
636: if (*ap == '\0')
637: continue;
638: if (*ap == '-') {
639: switch (*++ap) {
640: case 's':
641: ctp -> flags |= CONN_STRICT;
642: break;
643: case 't':
644: ctp -> flags |= CONN_TRANS;
645: break;
646: case 'n':
647: ctp -> flags |= CONN_NOMUNGE;
648: break;
649: case 'f':
650: ctp -> flags |= CONN_FORCEMUNGE;
651: break;
652:
653: default:
654: adios (NULLCP, "Unknown option -%c", *ap);
655: }
656: }
657: else {
658: if ((ta = str2taddr (ap)) == NULLTA)
659: adios (NULLCP, "Bad address \"%s\" in file %s",
660: ap, file);
661: ctp -> dest = *ta; /* struct copy */
662: ctp -> flags |= (CONN_TRANS|CONN_NOMUNGE);
663: }
664: }
665:
666: }
667:
668: if (strcmp (file, "-") != 0)
669: (void) fclose (fp);
670: }
671:
672: /* */
673:
674: static void envinit () {
675: int i,
676: sd;
677:
678: nbits = getdtablesize ();
679:
680: if (!(debug = isatty (2))) {
681: for (i = 0; i < 5; i++) {
682: switch (fork ()) {
683: case NOTOK:
684: sleep (5);
685: continue;
686:
687: case OK:
688: break;
689:
690: default:
691: _exit (0);
692: }
693: break;
694: }
695:
696: (void) chdir ("/");
697:
698: if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
699: adios ("/dev/null", "unable to read");
700: if (sd != 0)
701: (void) dup2 (sd, 0), (void) close (sd);
702: (void) dup2 (0, 1);
703: (void) dup2 (0, 2);
704:
705: #ifdef SETSID
706: if (setsid () == NOTOK)
707: advise (LLOG_EXCEPTIONS, "failed", "setsid");
708: #endif
709: #ifdef TIOCNOTTY
710: if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
711: (void) ioctl (sd, TIOCNOTTY, NULLCP);
712: (void) close (sd);
713: }
714: #else
715: #ifdef SYS5
716: (void) setpgrp ();
717: (void) signal (SIGINT, SIG_IGN);
718: (void) signal (SIGQUIT, SIG_IGN);
719: #endif
720: #endif
721: }
722: else
723: ll_dbinit (pgm_log, myname);
724:
725: #ifndef sun /* damn YP... */
726: for (sd = 3; sd < nbits; sd++)
727: if (pgm_log -> ll_fd != sd)
728: (void) close (sd);
729: #endif
730:
731: (void) signal (SIGPIPE, SIG_IGN);
732:
733: ll_hdinit (pgm_log, myname);
734: advise (LLOG_NOTICE, NULLCP, "starting");
735: }
736:
737: /* ERRORS */
738:
739: #ifndef lint
740: static void adios (va_alist)
741: va_dcl
742: {
743: va_list ap;
744:
745: va_start (ap);
746:
747: _ll_log (pgm_log, LLOG_FATAL, ap);
748:
749: va_end (ap);
750:
751: _exit (1);
752: }
753: #else
754: /* VARARGS */
755:
756: static void adios (what, fmt)
757: char *what,
758: *fmt;
759: {
760: adios (what, fmt);
761: }
762: #endif
763:
764:
765: #ifndef lint
766: static void advise (va_alist)
767: va_dcl
768: {
769: int code;
770: va_list ap;
771:
772: va_start (ap);
773:
774: code = va_arg (ap, int);
775:
776: _ll_log (pgm_log, code, ap);
777:
778: va_end (ap);
779: }
780: #else
781: /* VARARGS */
782:
783: static void advise (code, what, fmt)
784: char *what,
785: *fmt;
786: int code;
787: {
788: advise (code, what, fmt);
789: }
790: #endif
791:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.