386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 25 Feb 1991 19:38:15 +0000 (11:38 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 25 Feb 1991 19:38:15 +0000 (11:38 -0800)
Work on file usr/othersrc/contrib/isode/support/tsapd.c.tst

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/contrib/isode/support/tsapd.c.tst [new file with mode: 0644]

diff --git a/usr/othersrc/contrib/isode/support/tsapd.c.tst b/usr/othersrc/contrib/isode/support/tsapd.c.tst
new file mode 100644 (file)
index 0000000..397d2e8
--- /dev/null
@@ -0,0 +1,1625 @@
+/* tsapd.c - OSI transport listener */
+
+#ifndef        lint
+static char *rcsid = "$Header: /f/osi/support/RCS/tsapd.c,v 7.12 91/02/22 09:46:59 mrose Interim $";
+#endif
+
+/* 
+ * $Header: /f/osi/support/RCS/tsapd.c,v 7.12 91/02/22 09:46:59 mrose Interim $
+ *
+ *
+ * $Log:       tsapd.c,v $
+ * Revision 7.12  91/02/22  09:46:59  mrose
+ * Interim 6.8
+ * 
+ * Revision 7.11  90/12/19  09:16:14  mrose
+ * touch-up
+ * 
+ * Revision 7.10  90/12/17  22:13:27  mrose
+ * -call
+ * 
+ * Revision 7.9  90/12/11  10:52:29  mrose
+ * lock-and-load
+ * 
+ * Revision 7.8  90/11/05  14:10:32  mrose
+ * oops
+ * 
+ * Revision 7.7  90/10/30  14:25:32  mrose
+ * update
+ * 
+ * Revision 7.6  90/10/29  18:37:25  mrose
+ * updates
+ * 
+ * Revision 7.5  90/10/16  11:21:04  mrose
+ * update
+ * 
+ * Revision 7.4  90/10/15  22:54:26  mrose
+ * typo
+ * 
+ * Revision 7.3  90/10/15  18:18:47  mrose
+ * iaed
+ * 
+ * Revision 7.2  90/07/09  14:51:00  mrose
+ * sync
+ * 
+ * Revision 7.1  90/02/19  13:09:53  mrose
+ * update
+ * 
+ * Revision 7.0  89/11/23  22:27:46  mrose
+ * Release 6.0
+ * 
+ */
+
+/*
+ *                               NOTICE
+ *
+ *    Acquisition, use, and distribution of this module and related
+ *    materials are subject to the restrictions of a license agreement.
+ *    Consult the Preface in the User's Manual for the full terms of
+ *    this agreement.
+ *
+ */
+
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <varargs.h>
+#include "manifest.h"
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#ifdef BSD42
+#include <sys/file.h>
+#endif
+#ifdef SYS5
+#include <fcntl.h>
+#endif
+#ifndef        X_OK
+#define        X_OK    1
+#endif
+
+#ifdef IAE
+#include <quipu/util.h>
+#include <quipu/bind.h>
+#include <quipu/list.h>
+#include <quipu/ds_search.h>
+
+#define        NOGOSIP
+#endif
+
+#ifndef        NOGOSIP
+#include "rosap.h"
+#include "rtsap.h"
+#include "psap2.h"
+#include "ssap.h"
+#endif
+#include "tpkt.h"
+
+#ifdef TCP
+#include "internet.h"
+#endif
+#ifdef X25
+#include "x25.h"
+#endif
+#ifdef TP4
+#include "tp4.h"
+#endif
+#ifndef        IAE
+#include "isoservent.h"
+#endif
+#include "tailor.h"
+
+/* \f */
+
+static int  debug = 0;
+static int  nbits = FD_SETSIZE;
+
+static LLog _pgm_log = {
+#ifndef        IAE
+    "tsapd.log",
+#else
+    "iaed.log",
+#endif
+    NULLCP, NULLCP, LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE,
+    LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK
+};
+LLog *pgm_log = &_pgm_log;
+
+static char *pgmname = "tsapd";
+static char myhost[BUFSIZ];
+
+static int     tcpservice = 1;
+static int     x25service = 1;
+static int     bridgeservice = 1;
+static int     tp4service = 1;
+
+static int     *services[] = {
+    &tp4service, &tcpservice, &x25service, &bridgeservice
+};
+
+
+#define        NTADDRS FD_SETSIZE
+
+static int     listening = 0;
+
+static struct TSAPaddr *tz;
+static struct TSAPaddr  tas[NTADDRS];
+
+
+#ifdef IAE
+#define        IAETIME (24 * 60 * 60L)
+
+static int     isbound = 0;
+static int     main_dsa = NOTOK;
+static int     referral_dsa = NOTOK;
+
+static long    nextime;
+
+static DN      userdn = NULL;
+static char    passwd[DBA_MAX_PASSWD_LEN];
+
+static AttributeType t_ev;
+static AttributeType t_pa;
+
+static struct ds_search_arg search_arg;
+
+struct IAEntry {
+    struct TSAPaddr is_addr;
+
+    char    *is_vector;
+    char   **is_vec;
+    char   **is_tail;
+};
+
+#define        NENTRIES        100
+static struct IAEntry *iz;
+static struct IAEntry  iae[NENTRIES];
+
+
+int    str2dnY ();
+
+
+extern int     dsa_ad;
+extern int     dsa_dead;
+extern char   *local_dit;
+extern struct PSAPaddr dsa_bound;
+
+extern int     as_print (), dn_print (), de_print (), fi_print ();
+#endif
+
+
+void   adios (), advise ();
+void   ts_advise ();
+
+#ifdef NOGOSIP
+#define        ssapd   NULLIFP
+#else
+int    ssapd (), psapd ();
+#endif
+
+
+extern int  errno;
+
+#ifdef IAE
+long   time ();
+#endif
+
+/* \f */
+
+/* ARGSUSED */
+
+main (argc, argv, envp)
+int     argc;
+char  **argv,
+      **envp;
+{
+    int            failed,
+           vecp;
+    char   *vec[4];
+    register struct TSAPaddr  *ta;
+    struct TSAPdisconnect   tds;
+    register struct TSAPdisconnect  *td = &tds;
+
+    arginit (argv);
+    envinit ();
+
+    failed = 0;
+
+    for (ta = tas; ta < tz; ta++) {
+       register struct NSAPaddr *na;
+
+       if (ta -> ta_naddr) {
+           if (((na = ta -> ta_addrs) -> na_stack < 0
+                    || na -> na_stack
+                                   >= sizeof services / sizeof services[0]))
+               adios (NULLCP, "unknown network type 0x%x", na -> na_stack);
+       }
+       else
+           na = NULLNA;
+           
+       if (!*services[na ? na -> na_stack : NA_NSAP])
+           continue;
+
+       advise (LLOG_NOTICE, NULLCP, "listening on %s", taddr2str (ta));
+
+       if (TNetListen (ta, td) == NOTOK) {
+           ts_advise (td, LLOG_EXCEPTIONS, "TNetListen failed");
+           failed++;
+       }
+       else
+           listening++;
+    }
+
+    if (!listening)
+       adios (NULLCP, failed ? "no successful listens"
+                             : "no network services selected");
+
+    for (;;) {
+#ifdef IAE
+       int     secs;
+       long    now;
+
+       (void) time (&now);
+       now++;
+
+       if ((secs = (int) (nextime - now)) <= 0) {
+           search_directory (0);
+
+           secs = IAETIME;
+       }
+#else
+#define        secs    NOTOK
+#endif
+
+       if (TNetAccept (&vecp, vec, 0, NULLFD, NULLFD, NULLFD, secs, td)
+               == NOTOK) {
+           ts_advise (td, LLOG_EXCEPTIONS, "TNetAccept failed");
+           continue;
+       }
+
+       if (vecp <= 0)
+           continue;
+
+       if (debug)
+           break;
+
+       switch (TNetFork (vecp, vec, td)) {
+           case OK:
+#ifdef IAE
+               (void) signal (SIGHUP, SIG_DFL);
+#endif
+               ll_hdinit (pgm_log, pgmname);
+               break;
+
+           case NOTOK:
+               ts_advise (td, LLOG_EXCEPTIONS, "TNetFork failed");
+           default:
+               continue;
+       }
+       break;
+    }
+
+    tsapd (vecp, vec);
+}
+
+/* \f */
+
+static char buffer1[4096];
+static char buffer2[32768];
+
+
+static int  tsapd (vecp, vec)
+int    vecp;
+char  **vec;
+{
+    char    buffer[BUFSIZ];
+#ifndef        IAE
+    register struct isoservent *is;
+#else
+    register struct IAEntry *is;
+#endif
+    struct tsapblk *tb;
+    struct TSAPstart   tss;
+    register struct TSAPstart *ts = &tss;
+    struct TSAPdisconnect   tds;
+    register struct TSAPdisconnect  *td = &tds;
+    IFP            hook;
+
+/* begin UGLY */
+    (void) strcpy (buffer1, vec[1]);
+    (void) strcpy (buffer2, vec[2]);
+/* end UGLY */
+
+    if (TInit (vecp, vec, ts, td) == NOTOK) {
+       ts_advise (td, LLOG_EXCEPTIONS, "T-CONNECT.INDICATION");
+       return;
+    }
+
+/* used to print this in ssapd()... */
+    advise (LLOG_NOTICE, NULLCP,
+           "T-CONNECT.INDICATION: <%d, %s, %s, %d, %d>",
+           ts -> ts_sd,
+           taddr2str (&ts -> ts_calling), taddr2str (&ts -> ts_called),
+           ts -> ts_expedited, ts -> ts_tsdusize);
+
+    hook = ssapd;
+    if (ts -> ts_called.ta_selectlen) {
+#ifndef        IAE
+       if ((is = getisoserventbyselector ("tsap", ts -> ts_called.ta_selector,
+                                          ts -> ts_called.ta_selectlen))
+               == NULL) {
+#else
+       for (is = iae; is < iz; is++)
+           if (is -> is_addr.ta_selectlen == ts -> ts_called.ta_selectlen
+                   && bcmp (is -> is_addr.ta_selector,
+                            ts -> ts_called.ta_selector,
+                            is -> is_addr.ta_selectlen) == 0)
+               break;
+       if (is >= iz) {
+#endif
+           (void) sprintf (buffer, "OSI service tsap/%s not found",
+                           sel2str (ts -> ts_called.ta_selector,
+                                    ts -> ts_called.ta_selectlen, 1));
+           goto out;
+       }
+    }
+    else
+#ifndef        IAE
+       if (hook == NULLIFP
+               || (is = getisoserventbyname ("session", "tsap")) == NULL)
+#endif
+       {
+           (void) strcpy (buffer, "default session service not found");
+           goto out;
+       }
+
+#ifndef        IAE
+    *is -> is_tail++ = buffer1;
+    *is -> is_tail++ = buffer2;
+    *is -> is_tail = NULL;
+#else
+    is -> is_tail[0] = buffer1;
+    is -> is_tail[1] = buffer2;
+    is -> is_tail[2] = NULL;
+#endif
+
+    if (tb = findtblk (ts -> ts_sd))
+       tb -> tb_fd = NOTOK;
+    switch (hook ? (*hook) (is, td) : OK) {
+       case NOTOK:
+           ts_advise (td, LLOG_EXCEPTIONS, "service not started at tsap");
+       case DONE:
+           exit (1);
+           /* NOTREACHED */
+
+       case OK:
+       default:
+           (void) setperms (is);
+           { register char **lp = is->is_vec; int arg = 0;
+               while(*lp) {
+                       printf("arg %d is %s\n", arg, *lp);
+                       arg++; lp++;
+               }
+           }
+           (void) execv (*is -> is_vec, is -> is_vec);
+           (void) sprintf (buffer, "unable to exec %s: %s",
+                           *is -> is_vec, sys_errname (errno));
+           SLOG (pgm_log, LLOG_FATAL, NULLCP, ("%s", buffer));
+           break;
+    }
+
+out: ;
+    advise (LLOG_EXCEPTIONS, NULLCP, "%s", buffer);
+    if (strlen (buffer) >= TD_SIZE)
+       buffer[0] = NULL;
+    (void) TDiscRequest (ts -> ts_sd, buffer, strlen (buffer) + 1, td);
+
+    exit (1);
+}
+
+/* \f */
+
+static int  setperms (is)
+#ifndef        IAE
+register struct isoservent *is;
+#else
+register struct IAEntry *is;
+#endif
+{
+    struct stat st;
+
+    if (stat (*is -> is_vec, &st) == NOTOK) {
+       (void) setgid (1);
+       (void) setuid (1);
+    }
+    else {
+       (void) setgid (st.st_gid);
+       (void) setuid (st.st_uid);
+    }
+}
+
+/* \f */
+
+static void  ts_advise (td, code, event)
+register struct TSAPdisconnect *td;
+int    code;
+char   *event;
+{
+    char    buffer[BUFSIZ];
+
+    if (td -> td_cc > 0)
+       (void) sprintf (buffer, "[%s] %*.*s",
+               TErrString (td -> td_reason),
+               td -> td_cc, td -> td_cc, td -> td_data);
+    else
+       (void) sprintf (buffer, "[%s]", TErrString (td -> td_reason));
+
+    advise (code, NULLCP, "%s: %s", event, buffer);
+}
+
+/* \f */
+
+#ifndef        NOGOSIP
+static int  ssapd (is, td)
+register struct isoservent *is;
+register struct TSAPdisconnect *td;
+{
+    int            sd;
+    struct TSAPstart    tss;
+    register struct TSAPstart  *ts = &tss;
+    struct SSAPindication sis;
+    register struct SSAPabort *sa = &sis.si_abort;
+
+    if (strcmp (is -> is_entity, "session")
+           || strcmp (is -> is_provider, "tsap"))
+       return OK;
+
+    if (TInit (is -> is_tail - is -> is_vec, is -> is_vec, ts, td) == NOTOK)
+       return NOTOK;
+
+    sd = ts -> ts_sd;
+
+    if (TConnResponse (sd, &ts -> ts_called, ts -> ts_expedited, NULLCP, 0,
+                      NULLQOS, td) == NOTOK)
+       return NOTOK;
+
+    if (SExec (ts, &sis, psapd, setperms) == NOTOK) {
+       advise (LLOG_EXCEPTIONS, NULLCP, "service not started at ssap: %s",
+               SErrString (sa -> sa_reason));
+       if (sa -> sa_cc > 0)
+           advise (LLOG_EXCEPTIONS, NULLCP, "   %*.*s",
+                   sa -> sa_cc, sa -> sa_cc, sa -> sa_data);
+
+       SAFREE (sa);
+    }
+               
+    return DONE;
+}
+
+/* \f */
+
+#define        RMASK \
+    "\020\01HALFDUPLEX\02DUPLEX\03EXPEDITED\04MINORSYNC\05MAJORSYNC\06RESYNC\
+\07ACTIVITY\010NEGOTIATED\011CAPABILITY\012EXCEPTIONS\013TYPEDATA"
+
+
+static int  psapd (is, si)
+register struct isoservent *is;
+register struct SSAPindication *si;
+{
+    struct SSAPstart    sss;
+    register struct SSAPstart  *ss = &sss;
+    struct PSAPindication  pis;
+    register struct PSAPabort *pa = &pis.pi_abort;
+    struct RtSAPindication  rtis;
+    register struct RtSAPabort *rta = &rtis.rti_abort;
+    struct RoSAPindication  rois;
+    register struct RoSAPpreject   *rop = &rois.roi_preject;
+
+    if (strcmp (is -> is_provider, "ssap"))
+       return OK;
+
+    if (strcmp (is -> is_entity, "presentation")
+           && strcmp (is -> is_entity, "rts")
+           && strcmp (is -> is_entity, "ros"))
+       return OK;
+
+/* begin UGLY */
+    (void) strcpy (buffer1, *(is -> is_tail - 2));
+    (void) strcpy (buffer2, *(is -> is_tail - 1));
+/* end UGLY */
+    if (SInit (is -> is_tail - is -> is_vec, is -> is_vec, ss, si) == NOTOK)
+       return NOTOK;
+    advise (LLOG_NOTICE, NULLCP,
+           "S-CONNECT.INDICATION: <%d, %s, %s, %s, %s, %ld, %d>",
+           ss -> ss_sd, sprintref (&ss -> ss_connect),
+           saddr2str (&ss -> ss_calling), saddr2str (&ss -> ss_called),
+           sprintb (ss -> ss_requirements, RMASK), ss -> ss_isn,
+           ss -> ss_ssdusize);
+
+    if (strcmp (is -> is_entity, "presentation") == 0) {
+       if (PExec (ss, &pis, buffer1, buffer2, NULLIFP, setperms) == NOTOK) {
+               advise (LLOG_EXCEPTIONS, NULLCP,
+                       "service not started at psap: %s",
+                       PErrString (pa -> pa_reason));
+               if (pa -> pa_cc > 0)
+                   advise (LLOG_EXCEPTIONS, NULLCP, "   %*.*s",
+                       pa -> pa_cc, pa -> pa_cc, pa -> pa_data);
+       }
+
+       return DONE;
+    }
+
+    if (strcmp (is -> is_entity, "rts") == 0) {
+       if (RtExec (ss, &rtis, buffer1, buffer2, NULLIFP, setperms) == NOTOK) {
+           advise (LLOG_EXCEPTIONS, NULLCP,
+                   "service not started at rtsap: %s",
+                   RtErrString (rta -> rta_reason));
+           if (rta -> rta_cc > 0)
+               advise (LLOG_EXCEPTIONS, NULLCP, "   %*.*s",
+                       rta -> rta_cc, rta -> rta_cc, rta -> rta_data);
+       }
+    }
+    else {
+       if (RoExec (ss, &rois, buffer1, buffer2, NULLIFP, setperms) == NOTOK) {
+           advise (LLOG_EXCEPTIONS, NULLCP,
+                   "service not started at rosap: %s",
+                   RoErrString (rop -> rop_reason));
+           if (rop -> rop_cc > 0)
+               advise (LLOG_EXCEPTIONS, NULLCP, "   %*.*s",
+                       rop -> rop_cc, rop -> rop_cc, rop -> rop_data);
+       }
+    }
+
+    return DONE;
+}
+#endif
+
+/* \f */
+
+#ifndef        IAE
+static arginit (vec)
+char   **vec;
+{
+    int            rflag;
+    register char  *ap;
+#ifdef TCP
+    int            port;
+    struct NSAPaddr *tcp_na;
+    register struct servent *sp;
+#endif
+#ifdef X25
+    struct NSAPaddr *x25_na;
+#endif
+#ifdef BRIDGE_X25
+    struct NSAPaddr *bridge_na;
+#endif
+#ifdef TP4
+    register struct isoservent *is;
+#endif
+    struct stat st;
+
+    if (pgmname = rindex (*vec, '/'))
+       pgmname++;
+    if (pgmname == NULL || *pgmname == NULL)
+       pgmname = *vec;
+
+    isodetailor (pgmname, 0);
+    ll_hdinit (pgm_log, pgmname);
+
+    rflag = 0;
+
+    (void) strcpy (myhost, TLocalHostName ());
+
+    bzero ((char *) tas, sizeof tas);
+    tz = tas;
+
+#ifdef TCP
+    if (!(ts_stacks & TS_TCP))
+       tcpservice = 0;
+    if ((sp = getservbyname ("tsap", "tcp")) == NULL
+           && (sp = getservbyname ("iso-tsap", "tcp")) == NULL)
+       advise (LLOG_EXCEPTIONS, NULLCP, "tcp/tsap: unknown service");
+
+    tcp_na = tz -> ta_addrs;
+    tcp_na -> na_stack = NA_TCP;
+    tcp_na -> na_community = ts_comm_tcp_default;
+    tcp_na -> na_domain[0] = NULL;
+    tcp_na -> na_port = sp ? sp -> s_port : htons ((u_short) 102);
+    tz -> ta_naddr = 1;
+
+    tz++;
+#endif
+
+#ifdef X25
+    if (!(ts_stacks & TS_X25))
+       x25service = 0;
+
+    x25_na = tz -> ta_addrs;
+    x25_na -> na_stack = NA_X25;
+    x25_na -> na_community = ts_comm_x25_default;
+    if (x25_local_dte && *x25_local_dte) {
+       (void) strcpy (x25_na -> na_dte, x25_local_dte);
+       x25_na -> na_dtelen = strlen (x25_na -> na_dte);
+    }
+    if (x25_local_pid && *x25_local_pid)
+       x25_na -> na_pidlen =
+           str2sel (x25_local_pid, -1, x25_na -> na_pid, NPSIZE);
+    tz -> ta_naddr = 1;
+
+    tz++;
+#endif
+
+#ifdef BRIDGE_X25
+    if (!(ts_stacks & TS_BRG))
+       bridgeservice = 0;
+
+    bridge_na = tz -> ta_addrs;
+    bridge_na -> na_stack = NA_BRG;
+    bridge_na -> na_community = ts_comm_x25_default;
+    if (x25_bridge_listen && *x25_bridge_listen) {
+       (void) strcpy (bridge_na -> na_dte, x25_bridge_listen);
+       bridge_na -> na_dtelen = strlen (bridge_na -> na_dte);
+    }
+    if (x25_bridge_pid && *x25_bridge_pid)
+       bridge_na -> na_pidlen =
+           str2sel (x25_bridge_pid, -1, bridge_na -> na_pid, NPSIZE);
+    tz -> ta_naddr = 1;
+
+    tz++;
+#endif
+
+#ifdef TP4
+    if (!(ts_stacks & TS_TP4))
+       tp4service = 0;
+
+    (void) setisoservent (0);
+    while (is = getisoservent ())
+       if (strcmp (is -> is_provider, "tsap") == 0
+               && (strcmp (*is -> is_vec, "tsapd-bootstrap") == 0
+                       || access (*is -> is_vec, X_OK) != NOTOK)) {
+           if (strcmp (is -> is_entity, "isore") == 0)
+               continue;
+
+           if (tz >= tas + NTADDRS) {
+               advise (LLOG_EXCEPTIONS, NULLCP,
+                       "too many services, starting with %s",
+                       is -> is_entity);
+               break;
+           }
+
+           bcopy (is -> is_selector, tz -> ta_selector,
+                  tz -> ta_selectlen = is -> is_selectlen);
+           tz -> ta_naddr = 0;
+
+           tz++;
+       }
+    (void) endisoservent ();
+#endif
+
+    for (vec++; ap = *vec; vec++) {
+       if (*ap == '-')
+           switch (*++ap) {
+               case 'd':
+                   debug++;
+                   continue;
+               
+               case 't': 
+                   ts_stacks = TS_TCP;
+                   tcpservice = 1;
+                   x25service = bridgeservice = tp4service = 0;
+                   continue;
+
+               case 'x': 
+                   ts_stacks = TS_X25;
+                   x25service = 1;
+                   tcpservice = bridgeservice = tp4service = 0;
+                   continue;
+
+               case 'z': 
+                   ts_stacks = TS_TP4;
+                   tp4service = 1;
+                   tcpservice = x25service = bridgeservice = 0;
+                   continue;
+
+               case 'b':
+                   ts_stacks = TS_BRG;
+                   bridgeservice = 1;
+                   tcpservice = x25service = tp4service = 0;
+                   continue;
+
+               case 'r':
+                   rflag = 1;
+                   continue;
+
+#ifdef TCP
+               case 'p': 
+                   if ((ap = *++vec) == NULL
+                           || *ap == '-'
+                           || (port = atoi (ap)) <= 0)
+                       adios (NULLCP, "usage: %s -p portno", pgmname);
+                   tcp_na -> na_port = htons ((u_short) port);
+                   continue;
+#endif
+
+#ifdef X25
+               /* This permits listening on a specific subaddress. */
+               case 'a':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -a x121address", pgmname);
+                   (void) strcpy (x25_na -> na_dte, ap);
+                   x25_na -> na_dtelen = strlen (ap);
+                   continue;
+
+               /* This permits listening on a specific protocol id.
+                  In fact, SunLink X.25 lets you listen on a protocol
+                  id mask, but let's keep it simple. */
+               case 'i':
+                   if ((ap = *++vec) == NULL || *ap == '-' )
+                       adios (NULLCP, "usage: %s -i pid", pgmname);
+                   x25_na -> na_pidlen =
+                       str2sel (ap, -1, x25_na -> na_pid, NPSIZE);
+                   continue;
+#endif
+
+#ifdef BRIDGE_X25
+               case 'A':
+                   if ((ap = *++vec) == NULL ||
+                       *ap == '-')
+                       adios (NULLCP, "usage: %s -A x121address", pgmname);
+                   (void) strcpy (bridge_na -> na_dte, ap);
+                   bridge_na -> na_dtelen = strlen (ap);
+                   continue;
+
+               case 'I':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -I pid", pgmname);
+                   bridge_na -> na_pidlen =
+                       str2sel (ap, -1, bridge_na -> na_pid, NPSIZE);
+                   continue;
+#endif
+
+               default: 
+                   adios (NULLCP, "-%s: unknown switch", ap);
+           }
+
+       adios (NULLCP, "usage: %s [switches]", pgmname);
+    }
+
+    if (!rflag
+           && getuid () == 0
+           && stat (ap = isodefile ("isoservices", 0), &st) != NOTOK
+           && st.st_uid != 0)
+       adios (NULLCP, "%s not owned by root", ap);
+}
+
+/* \f */
+
+#else
+static arginit (vec)
+char   **vec;
+{
+    int            argp,
+           options;
+    register char *ap;
+    char    base[BUFSIZ],
+         **argptr,
+          *args[4];
+
+    if (pgmname = rindex (*vec, '/'))
+       pgmname++;
+    if (pgmname == NULL || *pgmname == NULL)
+       pgmname = *vec;
+
+    isodetailor (pgmname, 0);
+    ll_hdinit (pgm_log, pgmname);
+
+    quipu_syntaxes ();
+
+    argp = 0;
+    args[argp++] = pgmname;
+    for (argptr = vec, argptr++; ap = *argptr; argptr++) {
+       if (*ap == '-')
+           switch (*++ap) {
+               case 'D':
+               case 'u':
+               case 'p':
+                   if ((ap = *++argptr) == NULL || *ap == '-')
+                       break;
+                   continue;
+
+               case 'c':
+                   if ((ap = *++argptr) == NULL || *ap == '-')
+                       break;
+                   args[argp++] = "-c";
+                   args[argp++] = ap;
+                   break;
+
+               default:
+                   continue;
+            }
+
+       break;
+    }
+    args[argp] = NULLCP;
+
+    dsap_init (&argp, (argptr = args, &argptr));
+
+    (void) strcpy (myhost, TLocalHostName ());
+    (void) strcpy (base, local_dit);
+
+    if (!(ts_stacks & TS_TCP))
+       tcpservice = 0;
+    if (!(ts_stacks & TS_X25))
+       x25service = 0;
+    if (!(ts_stacks & TS_BRG))
+       bridgeservice = 0;
+    if (!(ts_stacks & TS_TP4))
+       tp4service = 0;
+
+    options = SVC_OPT_PREFERCHAIN;
+    userdn = NULLDN, passwd[0] = NULL;
+    for (vec++; ap = *vec; vec++) {
+       if (*ap == '-')
+           switch (*++ap) {
+               case 'd':
+                   debug++;
+                   ll_dbinit (pgm_log, pgmname);
+                   continue;
+               
+               case 't': 
+                   ts_stacks = TS_TCP;
+                   tcpservice = 1;
+                   x25service = bridgeservice = tp4service = 0;
+                   continue;
+
+               case 'x': 
+                   ts_stacks = TS_X25;
+                   x25service = 1;
+                   tcpservice = bridgeservice = tp4service = 0;
+                   continue;
+
+               case 'z': 
+                   ts_stacks = TS_TP4;
+                   tp4service = 1;
+                   tcpservice = x25service = bridgeservice = 0;
+                   continue;
+
+               case 'b':
+                   ts_stacks = TS_BRG;
+                   bridgeservice = 1;
+                   tcpservice = x25service = tp4service = 0;
+                   continue;
+
+               case 'r':       /* ignored... */
+                   continue;
+
+               case 'D':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -D DIT", pgmname);
+                   if (*ap == '@')
+                       (void) strcpy (base, ap);
+                   else
+                       (void) sprintf (base, "%s@%s", local_dit, ap);
+                   continue;
+
+               case 'm':
+                   options |= SVC_OPT_DONTUSECOPY;
+                   continue;
+
+               case 'c':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -c DSA-name-or-address",
+                              pgmname);
+                   continue;
+
+               case 'u':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -u username", pgmname);
+                   if ((userdn = str2dn (*ap != '@' ? ap : ap + 1)) == NULLDN)
+                       adios (NULLCP, "invalid DN for username: %s", ap);
+                   bzero ((char *) ap, strlen (ap));
+                   continue;
+
+               case 'p':
+                   if ((ap = *++vec) == NULL || *ap == '-')
+                       adios (NULLCP, "usage: %s -p password", pgmname);
+                   (void) strcpy (passwd, ap);
+                   bzero ((char *) ap, strlen (ap));
+                   continue;
+
+               default: 
+                   adios (NULLCP, "-%s: unknown switch", ap);
+           }
+
+       adios (NULLCP, "usage: %s [switches]", pgmname);
+    }
+
+    {
+       Attr_Sequence as;
+       AttributeType t_oc;
+       DN          local_dn;
+       register Filter fi;
+       register struct ds_search_arg *sa = &search_arg;
+
+       if ((t_ev = str2AttrT ("execVector")) == NULL)
+           adios (NULLCP, "unknown attribute type \"%s\"", "execVector");
+       if ((t_oc = str2AttrT ("objectClass")) == NULL)
+           adios (NULLCP, "unknown attribute type \"%s\"", "objectClass");
+       if ((t_pa = str2AttrT ("presentationAddress")) == NULL)
+           adios (NULLCP, "unknown attribute type \"%s\"",
+                  "presentationAddress");
+
+       if (str2dnY (*base != '@' ? base : base + 1, &local_dn) == NOTOK)
+           adios (NULLCP, "DIT subtree invalid: \"%s\"", base);
+
+       fi = filter_alloc ();
+       bzero ((char *) fi, sizeof *fi);
+
+       fi -> flt_type = FILTER_ITEM;
+       fi -> FUITEM.fi_type = FILTERITEM_EQUALITY;
+       fi -> FUITEM.UNAVA.ava_type = AttrT_cpy (t_oc);
+       if ((fi -> FUITEM.UNAVA.ava_value =
+                       str2AttrV ("iSODEApplicationEntity",
+                                  fi -> FUITEM.UNAVA.ava_type -> oa_syntax))
+               == NULL)
+           adios (NULLCP, "unknown attribute value \"%s\" for \"%s\"",
+                  "iSODEApplicationEntity", "objectClass");
+
+       as = as_merge (as_comp_new (AttrT_cpy (t_ev), NULLAV, NULLACL_INFO),
+                      as_comp_new (AttrT_cpy (t_pa), NULLAV, NULLACL_INFO));
+
+       bzero ((char *) sa, sizeof *sa);
+
+       sa -> sra_common.ca_servicecontrol.svc_options = options;
+       sa -> sra_common.ca_servicecontrol.svc_timelimit = SVC_NOTIMELIMIT;
+       sa -> sra_common.ca_servicecontrol.svc_sizelimit = SVC_NOSIZELIMIT;
+       sa -> sra_baseobject = local_dn;
+       sa -> sra_subset = SRA_WHOLESUBTREE;
+       sa -> sra_filter = fi;
+       sa -> sra_searchaliases = TRUE;
+       sa -> sra_eis.eis_allattributes = FALSE;
+       sa -> sra_eis.eis_select = as;
+       sa -> sra_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
+
+       search_directory (1);
+    }
+}
+
+/* \f */
+
+static search_directory (firstime)
+int    firstime;
+{
+    int            i;
+    register struct ds_search_arg *sa = &search_arg;
+    struct ds_search_result search_result;
+    register struct ds_search_result *sr = &search_result;
+    struct DSError error;
+    register struct DSError *se = &error;
+    register EntryInfo *ptr;
+    register struct IAEntry  *ia;
+    register struct TSAPaddr *ta,
+                            *tb,
+                            *ty;
+    struct TSAPaddr tys[NTADDRS];
+
+    advise (LLOG_NOTICE, NULLCP,
+           "searching directory for iSODEApplicationEntity objects");
+
+    while (rebind_to_directory () == NOTOK) {
+       if (!firstime)
+           return;
+       
+       if (debug)
+           advise (LLOG_DEBUG, NULLCP, "sleeping for 5 minutes...");
+       sleep ((unsigned) 5 * 60);
+    }
+
+    for (;;) {
+       if (debug) {
+           pslog (pgm_log, LLOG_DEBUG, "performing subtree search of",
+                  dn_print, (caddr_t) sa -> sra_baseobject);
+           pslog (pgm_log, LLOG_DEBUG, "  for", fi_print,
+                  (caddr_t) sa -> sra_filter);
+       }
+
+       if (ds_search (sa, se, sr) == DS_OK)
+           break;
+       if (do_error (se) == NOTOK) {
+           if (!firstime)
+               return;
+           
+           adios (NULLCP, "search failed");
+       }
+
+       sa -> sra_baseobject =
+                           se -> ERR_REFERRAL.DSE_ref_candidates -> cr_name;
+    }
+
+    if (sr -> srr_correlated != TRUE)
+       correlate_search_results (sr);
+
+    if (!firstime)
+       for (ia = iae; ia < iz; ia++) {
+           free (ia -> is_vector);
+           free (ia -> is_vec[0]);
+           free ((char *) ia -> is_vec);
+       }
+
+    bzero ((char *) iae, sizeof iae);
+    iz = iae;
+
+    bzero ((char *) tys, sizeof tys);
+    ty = tys;
+
+    i = 0;
+    for (ptr = sr -> CSR_entries; ptr; ptr = ptr -> ent_next) {
+       Attr_Sequence eptr;
+       AV_Sequence   avs;
+
+       if (iz >= iae + NENTRIES) {
+           pslog (pgm_log, LLOG_EXCEPTIONS,
+                  "too many services, starting with", dn_print,
+                  (caddr_t) ptr -> ent_dn);
+           break;
+       }
+
+       if (debug) {
+           pslog (pgm_log, LLOG_DEBUG, "processing", dn_print,
+                  (caddr_t) ptr -> ent_dn);
+           pslog (pgm_log, LLOG_DEBUG, "  attributes", as_print,
+                  (caddr_t) ptr -> ent_attr);
+       }
+
+       for (eptr = ptr -> ent_attr; eptr; eptr = eptr -> attr_link) {
+           if (AttrT_cmp (eptr -> attr_type, t_pa) == 0) {
+               if (avs = eptr -> attr_value) {
+                   register struct PSAPaddr *pa =
+                               (struct PSAPaddr *) avs -> avseq_av.av_struct;
+
+                   if ((ta = &pa -> pa_addr.sa_addr) -> ta_selectlen == 0
+                           || pa -> pa_selectlen > 0
+                           || pa -> pa_addr.sa_selectlen > 0)
+                       continue;
+                                               
+                   iz -> is_addr = *ta;        /* struct copy */
+               }
+
+               continue;
+           }
+           
+           if (AttrT_cmp (eptr -> attr_type, t_ev) == 0) {
+               if (avs = eptr -> attr_value) {
+                   int     vecp;
+                   register char  **vp;
+                   char   *cp,
+                          *evec[NVEC + NSLACK + 1];
+
+                   cp = (char *) avs -> avseq_av.av_struct;
+                   if ((iz -> is_vector =
+                                   malloc ((unsigned) (strlen (cp) + 1)))
+                           == NULL)
+                       adios (NULLCP, "out of memory allocating iaeVector");
+                   (void) strcpy (iz -> is_vector, cp);
+
+                   if ((vecp = str2vec (iz -> is_vector, evec)) < 1)
+                       goto losing_iae;
+                   if ((iz -> is_vec =
+                                   (char **) calloc ((unsigned) (vecp + 3),
+                                                     sizeof *iz -> is_vec))
+                           == NULL)
+                       adios (NULLCP, "out of memory allocating execVector");
+                   iz -> is_tail = iz -> is_vec, vp = evec;
+                   while (*iz -> is_tail++ = *vp++)
+                       continue;
+                   iz -> is_tail--;
+
+                   if (access (cp = isodefile (iz -> is_vec[0], 1), X_OK)
+                           == NOTOK) {
+                       advise (LLOG_EXCEPTIONS, cp, "unable to find program");
+                       iz -> is_vec[0] = NULL;
+                       goto losing_iae;
+                   }
+                   if ((iz -> is_vec[0] =
+                                       malloc ((unsigned) (strlen (cp) + 1)))
+                           == NULL)
+                       adios (NULLCP, "out of memory allocating pgmVector");
+                   (void) strcpy (iz -> is_vec[0], cp);
+               }
+               continue;
+           }
+       }
+       if ((ta = &iz -> is_addr) -> ta_selectlen == 0
+               || iz -> is_vector == NULL) {
+           pslog (pgm_log, LLOG_EXCEPTIONS, "invalid entry", dn_print,
+                  (caddr_t) ptr -> ent_dn);
+
+losing_iae: ;
+           if (iz -> is_vector)
+               free (iz -> is_vector);
+           if (iz -> is_vec) {
+               if (iz -> is_vec[0])
+                   free (iz -> is_vec[0]);
+               free ((char *) iz -> is_vec);
+           }
+           bzero ((char *) iz, sizeof *iz);
+           continue;
+       }
+
+       if (ta -> ta_naddr == 0)
+           *ty++ = *ta;                        /* struct copy */
+       else {
+           register int n = ta -> ta_naddr;
+           register struct NSAPaddr *na = ta -> ta_addrs;
+
+           for (; n > 0; na++, n--) {
+               for (tb = tys; tb < ty; tb++)
+                   if (tb -> ta_naddr != 0
+                           && bcmp ((char *) na, (char *) tb -> ta_addrs,
+                                    sizeof *na) == 0)
+                       break;
+               if (tb >= ty) {
+                   if (na -> na_type == NA_NSAP)
+                       bcopy (ta -> ta_selector, ty -> ta_selector,
+                              ty -> ta_selectlen = ta -> ta_selectlen);
+                   else
+                       ty -> ta_selectlen = 0;
+                   ty -> ta_naddr = 1;
+                   ty -> ta_addrs[0] = *na;    /* struct copy */
+
+                   ty++;
+               }
+           }
+       }
+
+       for (ia = iae; ia < iz; ia++) {
+           tb = &ia -> is_addr;
+
+           if (ta -> ta_selectlen == tb -> ta_selectlen
+                   && bcmp (ta -> ta_selector, tb -> ta_selector,
+                            ta -> ta_selectlen)  == 0) {
+               char    buffer[BUFSIZ];
+
+               (void) strcpy (buffer, taddr2str (tb));
+               advise (LLOG_EXCEPTIONS, NULLCP,
+                       "two services with the same transport selector: %s and %s",
+                       buffer, taddr2str (ta));
+               pslog (pgm_log, LLOG_EXCEPTIONS, "starting with", dn_print,
+                      (caddr_t) ptr -> ent_dn);
+               adios (NULLCP, "you lose big");
+           }
+       }
+
+       iz++, i++;
+    }
+
+    if (sr -> CSR_cr) {
+       advise (LLOG_EXCEPTIONS, NULLCP,
+               "partial results only (not all DSAs could be reached)");
+    }
+    else
+       if (sr -> CSR_limitproblem != LSR_NOLIMITPROBLEM) {
+           advise (LLOG_EXCEPTIONS, NULLCP, "%s limit exceeded",
+                   sr -> CSR_limitproblem == LSR_TIMELIMITEXCEEDED
+                           ? "time"
+                           : sr -> CSR_limitproblem == LSR_SIZELIMITEXCEEDED
+                                   ? "size" : "administrative");
+       }
+
+    if (i == 0)
+       adios (NULLCP, "search failed to find anything");
+    else
+       if (debug)
+           advise (LLOG_DEBUG, NULLCP, "%d match%s found",
+                   i, i != 1 ? "es" : "");
+
+    dn_free (sr -> CSR_object);
+    entryinfo_free (sr -> CSR_entries, 0);
+    crefs_free (sr -> CSR_cr);
+
+    (void) unbind_from_directory ();
+
+    if (!firstime) {
+       int     failed = 0;
+       struct TSAPdisconnect tds;
+
+       for (ta = tas; ta < tz; ta++) {
+           for (tb = tys; tb < ty; tb++)
+               if (bcmp ((char *) ta, (char *) tb, sizeof *ta) == 0)
+                   break;
+           if (tb >= ty) {
+               advise (LLOG_NOTICE, NULLCP, "closing %s", taddr2str (ta));
+
+               if (TNetClose (ta, &tds) == NOTOK)
+                   ts_advise (&tds, LLOG_EXCEPTIONS, "TNetClose failed");
+
+               listening--;
+           }
+       }
+
+       for (ta = tys; ta < ty; ta++) {
+           for (tb = tas; tb < tz; tb++)
+               if (bcmp ((char *) ta, (char *) tb, sizeof *ta) == 0)
+                   break;
+           if (tb >= tz) {
+               register struct NSAPaddr *na;
+
+               if (ta -> ta_naddr) {
+                   if (((na = ta -> ta_addrs) -> na_stack < 0
+                            || na -> na_stack
+                                   >= sizeof services / sizeof services[0]))
+                       adios (NULLCP, "unknown network type 0x%x",
+                              na -> na_stack);
+               }
+               else
+                   na = NULLNA;
+
+               if (!*services[na ? na -> na_stack : NA_NSAP])
+                   continue;
+
+               advise (LLOG_NOTICE, NULLCP, "listening on %s",
+                       taddr2str (ta));
+
+               if (TNetListen (ta, &tds) == NOTOK) {
+                   ts_advise (&tds, LLOG_EXCEPTIONS, "TNetListen failed");
+                   failed++;
+               }
+               else
+                   listening++;
+           }
+       }
+
+       if (!listening)
+           adios (NULLCP, failed ? "no successful listens"
+                                 : "no network services selected");
+
+    }
+    bzero ((char *) tas, sizeof tas);
+    tz = tas;
+
+    for (ta = tys; ta < ty; *tz++ = *ta++)     /* struct copy */
+       continue;
+
+    if (debug) {
+       advise (LLOG_DEBUG, NULLCP, "application entitites...");
+       for (ia = iae; ia < iz; ia++)
+           advise (LLOG_DEBUG, NULLCP, "  addr=%s vector=%s",
+                   taddr2str (&ia -> is_addr), ia -> is_vector);
+
+       advise (LLOG_DEBUG, NULLCP, "transport addresses...");
+       for (ta = tas; ta < tz; ta++)
+           advise (LLOG_DEBUG, NULLCP, "  addr=%s", taddr2str (ta));
+    }
+
+    (void) time (&nextime);
+    nextime += IAETIME;
+}
+
+/* \f */
+
+static bind_to_directory ()
+{
+    struct ds_bind_arg bind_arg,
+                      bind_result;
+    register struct ds_bind_arg *ba = &bind_arg,
+                               *br = &bind_result;
+    struct ds_bind_error bind_error;
+    register struct ds_bind_error *be = &bind_error;
+    static int very_first_time = 1;
+
+    (void) unbind_from_directory ();
+
+    make_bind_args (ba, br, be);
+
+    if (debug)
+       advise (LLOG_DEBUG, NULLCP, "connecting to DSA...");
+
+    if (secure_ds_bind (ba, be, br) != DS_OK) {
+       if (very_first_time)
+           very_first_time = 0;
+       else
+           advise (LLOG_EXCEPTIONS, NULLCP, "unable to connect: %s",
+                   be -> dbe_type == DBE_TYPE_SECURITY ? "security error"
+                                                       : "DSA unavailable");
+
+       isbound = 0;
+
+       return;
+    }
+    very_first_time = 0;
+    dn_free (br -> dba_dn);
+
+    main_dsa = dsap_ad;
+
+    advise (LLOG_NOTICE, NULLCP, "connected to %s", pa2str (&dsa_bound));
+
+    isbound = 1;
+}
+
+/* \f */
+
+static int  rebind_to_directory ()
+{
+    if (referral_dsa != NOTOK) {
+       if (debug)
+           advise (LLOG_DEBUG, NULLCP, "dap_unbind from referral dsa");
+
+       (void) dap_unbind (referral_dsa);
+       referral_dsa = NOTOK;
+       dsap_ad = main_dsa;
+    }
+
+    if (!isbound)
+       (void) bind_to_directory ();
+
+    return (isbound ? OK : NOTOK);
+}
+
+/* \f */
+
+static int     make_bind_args (ba, br, be)
+register struct ds_bind_arg *ba,
+                           *br;
+register struct ds_bind_error *be;
+{
+    bzero ((char *) ba, sizeof *ba);
+    bzero ((char *) br, sizeof *br);
+    bzero ((char *) be, sizeof *be);
+
+    ba -> dba_version = DBA_VERSION_V1988;
+    if (ba -> dba_dn = userdn)
+       ba -> dba_auth_type = DBA_AUTH_SIMPLE;
+    if (ba -> dba_passwd_len = strlen (passwd))
+       (void) strcpy (ba -> dba_passwd, passwd);
+}
+
+/* \f */
+
+static int  unbind_from_directory ()
+{
+    int            wasbound;
+
+    if (wasbound = isbound) {
+       if (referral_dsa != NOTOK) {
+           if (debug)
+               advise (LLOG_DEBUG, NULLCP, "dap_unbind from referral dsa");
+
+           (void) dap_unbind (referral_dsa);
+           referral_dsa = NOTOK;
+           dsap_ad = main_dsa;
+       }
+
+       (void) ds_unbind ();
+       isbound = 0;
+    }
+
+    dsa_dead = 0;
+
+    return wasbound;
+}
+
+/* \f */
+
+static int  do_error (de)
+register struct DSError *de;
+{
+    if (de -> dse_type == DSE_REFERRAL
+           && de -> ERR_REFERRAL.DSE_ref_candidates) {
+       register struct access_point *ap;
+       struct ds_bind_arg bind_arg,
+                          bind_result;
+       register struct ds_bind_arg *ba = &bind_arg,
+                                   *br = &bind_result;
+       struct ds_bind_error bind_error;
+       register struct ds_bind_error *be = &bind_error;
+
+       ap = de -> ERR_REFERRAL.DSE_ref_candidates -> cr_accesspoints;
+
+       if (referral_dsa != NOTOK) {
+           if (debug)
+               advise (LLOG_DEBUG, NULLCP, "dap_unbind from referral dsa");
+
+           (void) dap_unbind (referral_dsa);
+           referral_dsa = NOTOK;
+           dsap_ad = main_dsa;
+       }
+
+       make_bind_args (ba, br, be);    
+
+       pslog (pgm_log, LLOG_NOTICE, "referring to", dn_print,
+              (caddr_t) ap -> ap_name);
+
+       if (dap_bind (&referral_dsa, ba, be, br, ap -> ap_address) != DS_OK) {
+           advise (LLOG_EXCEPTIONS, NULLCP, "unable to connect: %s",
+                   be -> dbe_type == DBE_TYPE_SECURITY ? "security error"
+                                                       : "DSA unavailable");
+
+           dsap_ad = main_dsa;
+
+           ds_error_free (de);
+           return NOTOK;
+       }
+       dsap_ad = referral_dsa;
+
+       if (debug)
+           advise (LLOG_DEBUG, NULLCP, "referral in progress");
+
+       ds_error_free (de);
+       return OK;
+    }
+
+    pslog (pgm_log, LLOG_EXCEPTIONS, "DAP error:", de_print, (caddr_t) de);
+
+    if (dsa_dead) {
+       dsa_dead = 0;
+
+       if (referral_dsa != NOTOK) {
+           if (debug)
+               advise (LLOG_DEBUG, NULLCP, "dap_unbind from referral dsa");
+
+           (void) dap_unbind (referral_dsa);
+           referral_dsa = NOTOK;
+           dsap_ad = main_dsa;
+       }
+       else
+           (void) unbind_from_directory ();
+    }
+
+    return NOTOK;
+}
+
+/* \f */
+
+int    str2dnY (str, dn)
+char   *str;
+DN     *dn;
+{
+    if (*str == NULL) {
+       *dn = NULLDN;
+       return OK;
+    }
+
+    return ((*dn = str2dn (str)) != NULLDN ? OK : NOTOK);
+}
+
+/* \f */
+
+#ifdef BSD42
+/* ARGSUSED */
+#endif
+
+static SFD  hupser (sig)
+int    sig;
+{
+#ifndef        BSD42
+    (void) signal (sig, hupser);
+#endif
+
+    search_directory (0);
+}
+#endif
+
+/* \f */
+
+static  envinit () {
+    int     i,
+            sd;
+
+    nbits = getdtablesize ();
+
+    if (debug == 0 && !(debug = isatty (2))) {
+       for (i = 0; i < 5; i++) {
+           switch (fork ()) {
+               case NOTOK: 
+                   sleep (5);
+                   continue;
+
+               case OK: 
+                   break;
+
+               default: 
+                   _exit (0);
+           }
+           break;
+       }
+
+       (void) chdir ("/");
+
+       if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
+           adios ("/dev/null", "unable to read");
+       if (sd != 0)
+           (void) dup2 (sd, 0), (void) close (sd);
+       (void) dup2 (0, 1);
+       (void) dup2 (0, 2);
+
+#ifdef SETSID
+       if (setsid () == NOTOK)
+           advise (LLOG_EXCEPTIONS, "failed", "setsid");
+#endif
+#ifdef TIOCNOTTY
+       if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
+           (void) ioctl (sd, TIOCNOTTY, NULLCP);
+           (void) close (sd);
+       }
+#else
+#ifdef SYS5
+       (void) setpgrp ();
+       (void) signal (SIGINT, SIG_IGN);
+       (void) signal (SIGQUIT, SIG_IGN);
+#endif
+#endif
+    }
+    else
+       ll_dbinit (pgm_log, pgmname);
+
+#ifndef        sun             /* damn YP... */
+    for (sd = 3; sd < nbits; sd++)
+       if (pgm_log -> ll_fd != sd)
+           (void) close (sd);
+#endif
+
+    (void) signal (SIGPIPE, SIG_IGN);
+
+    ll_hdinit (pgm_log, pgmname);
+    advise (LLOG_NOTICE, NULLCP, "starting");
+
+#ifdef IAE
+       (void) signal (SIGHUP, hupser);
+#endif
+}
+
+/* \f   ERRORS */
+
+#ifndef        lint
+void   adios (va_alist)
+va_dcl
+{
+    va_list ap;
+
+    va_start (ap);
+    
+    _ll_log (pgm_log, LLOG_FATAL, ap);
+
+    va_end (ap);
+
+    _exit (1);
+}
+#else
+/* VARARGS */
+
+void   adios (what, fmt)
+char   *what,
+       *fmt;
+{
+    adios (what, fmt);
+}
+#endif
+
+
+#ifndef        lint
+void   advise (va_alist)
+va_dcl
+{
+    int            code;
+    va_list ap;
+
+    va_start (ap);
+    
+    code = va_arg (ap, int);
+
+    _ll_log (pgm_log, code, ap);
+
+    va_end (ap);
+}
+#else
+/* VARARGS */
+
+void   advise (code, what, fmt)
+char   *what,
+       *fmt;
+int    code;
+{
+    advise (code, what, fmt);
+}
+#endif