示例#1
0
/*-------------------------------------------------------------------*/
int http_command(int argc, char *argv[])
{
    int rc = 0;

    if ( !http_struct_init )
    {
        memset(&http_serv,0,sizeof(HTTP_SERV));
        initialize_condition( &http_serv.http_wait_shutdown );
        initialize_lock( &http_serv.http_lock_shutdown );
        initialize_lock( &http_lock_root );
        http_struct_init = TRUE;
    }

    http_serv.httpstmtold = FALSE;

    if ( argc == 2 && CMD(argv[0],rootx,4) &&
         ( ( strlen(argv[0]) == 5 && argv[2] != NULL && strcmp(argv[2],"httproot") == 0 ) ||
           ( strlen(argv[0]) == 4 ) ) )
    {
        if ( strlen(argv[0]) == 5 )
        {
            http_serv.httpstmtold = TRUE;
        }

        obtain_lock( &http_lock_root );
        if (http_serv.httproot)
        {
            free(http_serv.httproot);
            http_serv.httproot = NULL;
        }

        if ( strlen(argv[1]) > 0 )
        {
            char    pathname[MAX_PATH];

            hostpath(pathname, argv[1], sizeof(pathname));

            if ( pathname[strlen(pathname)-1] != PATHSEPC )
                strlcat( pathname, PATHSEPS, sizeof(pathname) );

            http_serv.httproot = strdup(pathname);
        }
        release_lock( &http_lock_root );

        http_root();

        if ( MLVL(VERBOSE) )
            WRMSG(HHC02204, "I", http_serv.httpstmtold ? "httproot": "root",
                        http_serv.httproot ? http_serv.httproot : "<not specified>");

        if ( http_serv.httpstmtold )
            http_startup(TRUE);

        rc = 0;
    }
    else if ( (argc == 2 || argc == 3 || argc == 5) && CMD(argv[0],portx,4) &&
              ( ( strlen(argv[0]) == 5 && argv[5] != NULL && strcmp(argv[5],"httpport") == 0 ) ||
                ( strlen(argv[0]) == 4 ) ) )
    {
        if ( strlen(argv[0]) == 5 )
        {
            http_serv.httpstmtold = TRUE;
        }

        if ( sysblk.httptid != 0 )
        {
            WRMSG( HHC01812, "E" );
            rc = -1;
        }
        else
        {
            char c;

            if (sscanf(argv[1], "%hu%c", &http_serv.httpport, &c) != 1
                    || http_serv.httpport == 0
                    || (http_serv.httpport < 1024 && http_serv.httpport != 80) )
            {
                rc = -1;
            }
            if ( rc >= 0 && argc == 3 && CMD(argv[2],noauth,6) )
            {
                http_serv.httpauth = 0;
            }
            else if ( rc >=0 && argc == 5 && CMD(argv[2],auth,4) )
            {
                if ( strlen( argv[3] ) < 1 || strlen( argv[4] ) < 1 )
                {
                    WRMSG( HHC01814, "E" );
                    rc = -1;
                }
                else
                {
                    if (http_serv.httpuser)
                        free(http_serv.httpuser);
                    http_serv.httpuser = strdup(argv[3]);

                    if (http_serv.httppass)
                        free(http_serv.httppass);
                    http_serv.httppass = strdup(argv[4]);

                    http_serv.httpauth = 1;
                }
            }
            else if ( argc != 2 || rc < 0 )
            {
                WRMSG( HHC02299, "E", "http" );
                rc = -1;
            }

            if ( rc >= 0 && MLVL(VERBOSE) )
            {
                char msgbuf[128];
                if ( http_serv.httpauth == 1 )
                {
                    MSGBUF( msgbuf, "port=%hu auth userid<%s> password<%s>",
                            http_serv.httpport,
                          ( http_serv.httpuser == NULL || strlen(http_serv.httpuser) == 0 ) ?
                                "" : http_serv.httpuser,
                          ( http_serv.httppass == NULL || strlen(http_serv.httppass) == 0 ) ?
                                "" : http_serv.httppass );
                }
                else
                    MSGBUF( msgbuf, "port=%hu noauth", http_serv.httpport );

                WRMSG( HHC02204, "I", http_serv.httpstmtold ? "httpport":"port", msgbuf );

                if ( http_serv.httpstmtold )
                    http_startup(TRUE);

            }   /* VERBOSE */
        }
    }
    else if ( argc == 1 && CMD(argv[0],start,3) )
    {
        if ( http_serv.httpport == 0 )
        {
            WRMSG( HHC01815, "E", "not valid");
            rc = -1;
        }
        else
            rc = http_startup(FALSE);
    }
    else if (argc == 1 && CMD(argv[0],stop,4))
    {
        if ( sysblk.httptid != 0 )
        {
            http_shutdown(NULL);
            WRMSG( HHC01805, "I" );
            rc = 1;
        }
        else
        {
            http_serv.httpshutdown = TRUE;
            WRMSG( HHC01806, "W", "already stopped" );
            rc = 1;
        }
    }
    else if ( argc == 0 )
    {
        if ( sysblk.httptid != 0 )
        {
            if ( http_serv.httpbinddone )
            {
                WRMSG( HHC01809, "I" );
                rc = 0;
            }
            else
            {
                WRMSG( HHC01813, "I" );
                rc = 1;
            }
        }
        else
        {
            WRMSG( HHC01810, "I" );
            rc = 1;
        }

        WRMSG(HHC01811, "I", http_get_root());

        WRMSG(HHC01808, "I", http_get_port(), http_get_portauth());
    }
    else
    {
        WRMSG( HHC02299, "E", "http" );
        rc = -1;
    }
    return rc;
}
示例#2
0
DLL_EXPORT void strerror_r_init(void)
{
    initialize_lock(&strerror_lock);
}
示例#3
0
int  CTCI_Init( DEVBLK* pDEVBLK, int argc, char *argv[] )
{
    PCTCBLK         pWrkCTCBLK = NULL;  // Working CTCBLK
    PCTCBLK         pDevCTCBLK = NULL;  // Device  CTCBLK
    int             rc = 0;             // Return code
    int             nIFType;            // Interface type
    int             nIFFlags;           // Interface flags
    char            thread_name[32];    // CTCI_ReadThread

    nIFType =               // Interface type
        0
        | IFF_TUN           // ("TUN", not "tap")
        | IFF_NO_PI         // (no packet info)
        ;

    nIFFlags =               // Interface flags
        0
        | IFF_UP            // (interface is being enabled)
        | IFF_BROADCAST     // (interface broadcast addr is valid)
        ;

#if defined( TUNTAP_IFF_RUNNING_NEEDED )

    nIFFlags |=             // ADDITIONAL Interface flags
        0
        | IFF_RUNNING       // (interface is ALSO operational)
        ;

#endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */

    pDEVBLK->devtype = 0x3088;

    // CTC is a group device
    if(!group_device(pDEVBLK, CTC_DEVICES_IN_GROUP))
        return 0;

    // Housekeeping
    pWrkCTCBLK = malloc( sizeof( CTCBLK ) );

    if( !pWrkCTCBLK )
    {
        logmsg( _("HHCCT037E %4.4X: Unable to allocate CTCBLK\n"),
                pDEVBLK->devnum );
        return -1;
    }

    memset( pWrkCTCBLK, 0, sizeof( CTCBLK ) );

    // Parse configuration file statement
    if( ParseArgs( pDEVBLK, pWrkCTCBLK, argc, (char**)argv ) != 0 )
    {
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }

    // Allocate the device CTCBLK and copy parsed information.

    pDevCTCBLK = malloc( sizeof( CTCBLK ) );

    if( !pDevCTCBLK )
    {
        logmsg( _("HHCCT038E %4.4X: Unable to allocate CTCBLK\n"),
                pDEVBLK->devnum );
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }

    memcpy( pDevCTCBLK, pWrkCTCBLK, sizeof( CTCBLK ) );

    // New format has only one device statement for both addresses
    // We need to dynamically allocate the read device block

    pDevCTCBLK->pDEVBLK[0] = pDEVBLK->group->memdev[0];
    pDevCTCBLK->pDEVBLK[1] = pDEVBLK->group->memdev[1];

    pDevCTCBLK->pDEVBLK[0]->dev_data = pDevCTCBLK;
    pDevCTCBLK->pDEVBLK[1]->dev_data = pDevCTCBLK;

    SetSIDInfo( pDevCTCBLK->pDEVBLK[0], 0x3088, 0x08, 0x3088, 0x01 );
    SetSIDInfo( pDevCTCBLK->pDEVBLK[1], 0x3088, 0x08, 0x3088, 0x01 );

    pDevCTCBLK->pDEVBLK[0]->ctctype  = CTC_CTCI;
    pDevCTCBLK->pDEVBLK[0]->ctcxmode = 1;

    pDevCTCBLK->pDEVBLK[1]->ctctype  = CTC_CTCI;
    pDevCTCBLK->pDEVBLK[1]->ctcxmode = 1;

    pDevCTCBLK->sMTU                = atoi( pDevCTCBLK->szMTU );
    pDevCTCBLK->iMaxFrameBufferSize = sizeof(pDevCTCBLK->bFrameBuffer);

    initialize_lock( &pDevCTCBLK->Lock );
    initialize_lock( &pDevCTCBLK->EventLock );
    initialize_condition( &pDevCTCBLK->Event );

    // Give both Herc devices a reasonable name...

    strlcpy( pDevCTCBLK->pDEVBLK[0]->filename,
             pDevCTCBLK->szTUNCharName,
     sizeof( pDevCTCBLK->pDEVBLK[0]->filename ) );

    strlcpy( pDevCTCBLK->pDEVBLK[1]->filename,
             pDevCTCBLK->szTUNCharName,
     sizeof( pDevCTCBLK->pDEVBLK[1]->filename ) );

    rc = TUNTAP_CreateInterface( pDevCTCBLK->szTUNCharName,
                                 IFF_TUN | IFF_NO_PI,
                                 &pDevCTCBLK->fd,
                                 pDevCTCBLK->szTUNDevName );

    if( rc < 0 )
    {
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }
    else
    {
        logmsg(_("HHCCT073I %4.4X: TUN device %s opened\n"),
                  pDevCTCBLK->pDEVBLK[0]->devnum,
                  pDevCTCBLK->szTUNDevName);
    }

#if defined(OPTION_W32_CTCI)

    // Set the specified driver/dll i/o buffer sizes..
    {
        struct tt32ctl tt32ctl;

        memset( &tt32ctl, 0, sizeof(tt32ctl) );
        strlcpy( tt32ctl.tt32ctl_name, pDevCTCBLK->szTUNDevName, sizeof(tt32ctl.tt32ctl_name) );

        tt32ctl.tt32ctl_devbuffsize = pDevCTCBLK->iKernBuff;
        if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0  )
        {
            logmsg( _("HHCCT074W TT32SDEVBUFF failed for device %s: %s.\n"),
                    pDevCTCBLK->szTUNDevName, strerror( errno ) );
        }

        tt32ctl.tt32ctl_iobuffsize = pDevCTCBLK->iIOBuff;
        if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0  )
        {
            logmsg( _("HHCCT075W TT32SIOBUFF failed for device %s: %s.\n"),
                    pDevCTCBLK->szTUNDevName, strerror( errno ) );
        }
    }
#endif

#ifdef OPTION_TUNTAP_CLRIPADDR
    VERIFY( TUNTAP_ClrIPAddr ( pDevCTCBLK->szTUNDevName ) == 0 );
#endif

#ifdef OPTION_TUNTAP_SETMACADDR

    if( !pDevCTCBLK->szMACAddress[0] )   // (if MAC address unspecified)
    {
        in_addr_t  wrk_guest_ip_addr;
        MAC        wrk_guest_mac_addr;

        if ((in_addr_t)-1 != (wrk_guest_ip_addr = inet_addr( pDevCTCBLK->szGuestIPAddr )))
        {
            build_herc_iface_mac ( wrk_guest_mac_addr, (const BYTE*) &wrk_guest_ip_addr );

            snprintf
            (
                pDevCTCBLK->szMACAddress,  sizeof( pDevCTCBLK->szMACAddress ),

                "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"

                ,wrk_guest_mac_addr[0]
                ,wrk_guest_mac_addr[1]
                ,wrk_guest_mac_addr[2]
                ,wrk_guest_mac_addr[3]
                ,wrk_guest_mac_addr[4]
                ,wrk_guest_mac_addr[5]
            );
        }
    }

    TRACE
    (
        "** CTCI_Init: %4.4X (%s): IP \"%s\"  -->  default MAC \"%s\"\n"

        ,pDevCTCBLK->pDEVBLK[0]->devnum
        ,pDevCTCBLK->szTUNDevName
        ,pDevCTCBLK->szGuestIPAddr
        ,pDevCTCBLK->szMACAddress
    );

    VERIFY( TUNTAP_SetMACAddr ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMACAddress  ) == 0 );
#endif

    VERIFY( TUNTAP_SetIPAddr  ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szDriveIPAddr ) == 0 );

    VERIFY( TUNTAP_SetDestAddr( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szGuestIPAddr ) == 0 );

#ifdef OPTION_TUNTAP_SETNETMASK
    VERIFY( TUNTAP_SetNetMask ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szNetMask     ) == 0 );
#endif

    VERIFY( TUNTAP_SetMTU     ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMTU         ) == 0 );

    VERIFY( TUNTAP_SetFlags   ( pDevCTCBLK->szTUNDevName, nIFFlags                  ) == 0 );

    // Copy the fd to make panel.c happy
    pDevCTCBLK->pDEVBLK[0]->fd =
    pDevCTCBLK->pDEVBLK[1]->fd = pDevCTCBLK->fd;

    snprintf(thread_name,sizeof(thread_name),"CTCI %4.4X ReadThread",pDEVBLK->devnum);
    thread_name[sizeof(thread_name)-1]=0;
    create_thread( &pDevCTCBLK->tid, JOINABLE, CTCI_ReadThread, pDevCTCBLK, thread_name );

    pDevCTCBLK->pDEVBLK[0]->tid = pDevCTCBLK->tid;
    pDevCTCBLK->pDEVBLK[1]->tid = pDevCTCBLK->tid;

    free( pWrkCTCBLK );
    pWrkCTCBLK = NULL;

    return 0;
}
示例#4
0
文件: impl.c 项目: rbowler/spinhawk
/*-------------------------------------------------------------------*/
DLL_EXPORT int impl(int argc, char *argv[])
{
    char   *cfgfile;                        /* -> Configuration filename */
    int     c;                              /* Work area for getopt      */
    int     arg_error = 0;                  /* 1=Invalid arguments       */
    char   *msgbuf;                         /*                           */
    int     msgnum;                         /*                           */
    int     msgcnt;                         /*                           */
    TID     rctid;                          /* RC file thread identifier */
    TID     logcbtid;                       /* RC file thread identifier */

    SET_THREAD_NAME("impl");

    /* Initialize 'hostinfo' BEFORE display_version is called */
    init_hostinfo( &hostinfo );

#ifdef _MSVC_
    /* Initialize sockets package */
    VERIFY( socket_init() == 0 );
#endif

    /* Ensure hdl_shut is called in case of shutdown
       hdl_shut will ensure entries are only called once */
    atexit(hdl_shut);

    set_codepage(NULL);

    /* Clear the system configuration block */
    memset (&sysblk, 0, sizeof(SYSBLK));

    /* Save thread ID of main program */
    sysblk.impltid = thread_id();

    /* Save TOD of when we were first IMPL'ed */
    time( &sysblk.impltime );

#ifdef OPTION_MSGHLD
    /* Set the default timeout value */
    sysblk.keep_timeout_secs = 120;
#endif

    /* Initialize thread creation attributes so all of hercules
       can use them at any time when they need to create_thread
    */
    initialize_detach_attr (DETACHED);
    initialize_join_attr   (JOINABLE);

    /* Copy length for regs */
    sysblk.regs_copy_len = (int)((uintptr_t)&sysblk.dummyregs.regs_copy_end
                                 - (uintptr_t)&sysblk.dummyregs);

    /* Set the daemon_mode flag indicating whether we running in
       background/daemon mode or not (meaning both stdout/stderr
       are redirected to a non-tty device). Note that this flag
       needs to be set before logger_init gets called since the
       logger_logfile_write function relies on its setting.
    */
    sysblk.daemon_mode = !isatty(STDERR_FILENO) && !isatty(STDOUT_FILENO);

    /* Initialize the logmsg pipe and associated logger thread.
       This causes all subsequent logmsg's to be redirected to
       the logger facility for handling by virtue of stdout/stderr
       being redirected to the logger facility.
    */
    logger_init();

    /* Now display the version information again after logger_init
       has been called so that either the panel display thread or the
       external gui can see the version which was previously possibly
       only displayed to the actual physical screen the first time we
       did it further above (depending on whether we're running in
       daemon_mode (external gui mode) or not). This it the call that
       the panel thread or the one the external gui actually "sees".
       The first call further above wasn't seen by either since it
       was issued before logger_init was called and thus got written
       directly to the physical screen whereas this one will be inter-
       cepted and handled by the logger facility thereby allowing the
       panel thread or external gui to "see" it and thus display it.
    */
    display_version (stdout, "Hercules ", TRUE);

#if defined(OPTION_DYNAMIC_LOAD)
    /* Initialize the hercules dynamic loader */
    hdl_main();
#endif /* defined(OPTION_DYNAMIC_LOAD) */

#ifdef EXTERNALGUI
    /* Set GUI flag if specified as final argument */
    if (argc >= 1 && strncmp(argv[argc-1],"EXTERNALGUI",11) == 0)
    {
#if defined(OPTION_DYNAMIC_LOAD)
        if (hdl_load("dyngui",HDL_LOAD_DEFAULT) != 0)
        {
            usleep(10000); /* (give logger thread time to issue
                               preceding HHCHD007E message) */
            logmsg(_("HHCIN008S DYNGUI.DLL load failed; Hercules terminated.\n"));
            delayed_exit(1);
        }
#endif /* defined(OPTION_DYNAMIC_LOAD) */
        argc--;
    }
#endif /*EXTERNALGUI*/

#if !defined(WIN32) && !defined(HAVE_STRERROR_R)
    strerror_r_init();
#endif

#if defined(OPTION_SCSI_TAPE)
    initialize_lock (&sysblk.stape_lock);
    initialize_condition (&sysblk.stape_getstat_cond);
    InitializeListHead (&sysblk.stape_mount_link);
    InitializeListHead (&sysblk.stape_status_link);
#endif /* defined(OPTION_SCSI_TAPE) */

    /* Get name of configuration file or default to hercules.cnf */
    if(!(cfgfile = getenv("HERCULES_CNF")))
        cfgfile = "hercules.cnf";

    /* Process the command line options */
    while ((c = getopt(argc, argv, "f:p:l:db:")) != EOF)
    {

        switch (c) {
        case 'f':
            cfgfile = optarg;
            break;
#if defined(OPTION_DYNAMIC_LOAD)
        case 'p':
            if(optarg)
                hdl_setpath(strdup(optarg));
            break;
        case 'l':
        {
            char *dllname, *strtok_str;
            for(dllname = strtok_r(optarg,", ",&strtok_str);
                    dllname;
                    dllname = strtok_r(NULL,", ",&strtok_str))
                hdl_load(dllname, HDL_LOAD_DEFAULT);
        }
        break;
#endif /* defined(OPTION_DYNAMIC_LOAD) */
        case 'b':
            sysblk.logofile=optarg;
            break;
        case 'd':
            sysblk.daemon_mode = 1;
            break;
        default:
            arg_error = 1;

        } /* end switch(c) */
    } /* end while */

    if (optind < argc)
        arg_error = 1;

    /* Terminate if invalid arguments were detected */
    if (arg_error)
    {
        logmsg("usage: %s [-f config-filename] [-d] [-b logo-filename]"
#if defined(OPTION_DYNAMIC_LOAD)
               " [-p dyn-load-dir] [[-l dynmod-to-load]...]"
#endif /* defined(OPTION_DYNAMIC_LOAD) */
               " [> logfile]\n",
               argv[0]);
        delayed_exit(1);
    }

    /* Register the SIGINT handler */
    if ( signal (SIGINT, sigint_handler) == SIG_ERR )
    {
        logmsg(_("HHCIN001S Cannot register SIGINT handler: %s\n"),
               strerror(errno));
        delayed_exit(1);
    }

    /* Register the SIGTERM handler */
    if ( signal (SIGTERM, sigterm_handler) == SIG_ERR )
    {
        logmsg(_("HHCIN009S Cannot register SIGTERM handler: %s\n"),
               strerror(errno));
        delayed_exit(1);
    }

#if defined( _MSVC_ )
    /* Register the Window console ctrl handlers */
    if (SetConsoleCtrlHandler(console_ctrl_handler, TRUE) == FALSE)
    {
        logmsg(_("HHCIN010S Cannot register ConsoleCtrl handler: %s\n"),
               strerror(errno));
        delayed_exit(1);
    }
#endif

#if defined(HAVE_DECL_SIGPIPE) && HAVE_DECL_SIGPIPE
    /* Ignore the SIGPIPE signal, otherwise Hercules may terminate with
       Broken Pipe error if the printer driver writes to a closed pipe */
    if ( signal (SIGPIPE, SIG_IGN) == SIG_ERR )
    {
        logmsg(_("HHCIN002E Cannot suppress SIGPIPE signal: %s\n"),
               strerror(errno));
    }
#endif

#if defined( OPTION_WAKEUP_SELECT_VIA_PIPE )
    {
        int fds[2];
        initialize_lock(&sysblk.cnslpipe_lock);
        initialize_lock(&sysblk.sockpipe_lock);
        sysblk.cnslpipe_flag=0;
        sysblk.sockpipe_flag=0;
        VERIFY( create_pipe(fds) >= 0 );
        sysblk.cnslwpipe=fds[1];
        sysblk.cnslrpipe=fds[0];
        VERIFY( create_pipe(fds) >= 0 );
        sysblk.sockwpipe=fds[1];
        sysblk.sockrpipe=fds[0];
    }
#endif // defined( OPTION_WAKEUP_SELECT_VIA_PIPE )

#if !defined(NO_SIGABEND_HANDLER)
    {
        struct sigaction sa;
        sa.sa_sigaction = (void*)&sigabend_handler;
#ifdef SA_NODEFER
        sa.sa_flags = SA_NODEFER;
#else
        sa.sa_flags = 0;
#endif

        /* Explictily initialize sa_mask to its default.        @PJJ */
        sigemptyset(&sa.sa_mask);

        if( sigaction(SIGILL, &sa, NULL)
                || sigaction(SIGFPE, &sa, NULL)
                || sigaction(SIGSEGV, &sa, NULL)
                || sigaction(SIGBUS, &sa, NULL)
                || sigaction(SIGUSR1, &sa, NULL)
                || sigaction(SIGUSR2, &sa, NULL) )
        {
            logmsg(_("HHCIN003S Cannot register SIGILL/FPE/SEGV/BUS/USR "
                     "handler: %s\n"),
                   strerror(errno));
            delayed_exit(1);
        }
    }
#endif /*!defined(NO_SIGABEND_HANDLER)*/

    /* Build system configuration */
    build_config (cfgfile);

    /* System initialisation time */
    sysblk.todstart = hw_clock() << 8;

#ifdef OPTION_MIPS_COUNTING
    /* Initialize "maxrates" command reporting intervals */
    curr_int_start_time = time( NULL );
    prev_int_start_time = curr_int_start_time;
#endif

#if !defined(NO_SIGABEND_HANDLER)
    /* Start the watchdog */
    if ( create_thread (&sysblk.wdtid, DETACHED,
                        watchdog_thread, NULL, "watchdog_thread") )
    {
        logmsg(_("HHCIN004S Cannot create watchdog thread: %s\n"),
               strerror(errno));
        delayed_exit(1);
    }
#endif /*!defined(NO_SIGABEND_HANDLER)*/

#ifdef OPTION_SHARED_DEVICES
    /* Start the shared server */
    if (sysblk.shrdport)
        if ( create_thread (&sysblk.shrdtid, DETACHED,
                            shared_server, NULL, "shared_server") )
        {
            logmsg(_("HHCIN006S Cannot create shared_server thread: %s\n"),
                   strerror(errno));
            delayed_exit(1);
        }

    /* Retry pending connections */
    {
        DEVBLK *dev;
        TID     tid;

        for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
            if (dev->connecting)
                if ( create_thread (&tid, DETACHED,
                                    *dev->hnd->init, dev, "device connecting thread")
                   )
                {
                    logmsg(_("HHCIN007S Cannot create %4.4X connection thread: %s\n"),
                           dev->devnum, strerror(errno));
                    delayed_exit(1);
                }
    }
#endif

    /* Start up the RC file processing thread */
    create_thread(&rctid,DETACHED,
                  process_rc_file,NULL,"process_rc_file");

    if(log_callback)
    {
        // 'herclin' called us. IT'S in charge. Create its requested
        // logmsg intercept callback function and return back to it.
        create_thread(&logcbtid,DETACHED,
                      log_do_callback,NULL,"log_do_callback");
        return(0);
    }

    //---------------------------------------------------------------
    // The below functions will not return until Hercules is shutdown
    //---------------------------------------------------------------

    /* Activate the control panel */
    if(!sysblk.daemon_mode)
        panel_display ();
    else
    {
#if defined(OPTION_DYNAMIC_LOAD)
        if(daemon_task)
            daemon_task ();
        else
#endif /* defined(OPTION_DYNAMIC_LOAD) */
        {
            /* Tell RC file and HAO threads they may now proceed */
            sysblk.panel_init = 1;

            /* Retrieve messages from logger and write to stderr */
            while (1)
                if((msgcnt = log_read(&msgbuf, &msgnum, LOG_BLOCK)))
                    if(isatty(STDERR_FILENO))
                        fwrite(msgbuf,msgcnt,1,stderr);
        }
    }

    //  -----------------------------------------------------
    //      *** Hercules has been shutdown (PAST tense) ***
    //  -----------------------------------------------------

    ASSERT( sysblk.shutdown );  // (why else would we be here?!)

#ifdef _MSVC_
    SetConsoleCtrlHandler(console_ctrl_handler, FALSE);
    socket_deinit();
#endif
#ifdef DEBUG
    fprintf(stdout, _("IMPL EXIT\n"));
#endif
    fprintf(stdout, _("HHCIN099I Hercules terminated\n"));
    fflush(stdout);
    usleep(10000);
    return 0;
} /* end function main */