⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sflproc.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 3 页
字号:
    ---------------------------------------------------------------------[>]-*/

int
process_server (
    const char *workdir,                /*  Where server runs, or NULL/""    */
    const char *lockfile,               /*  For exclusive execution          */
    int   argc,                         /*  Original command-line arguments  */
    char *argv [],                      /*  Original command-line arguments  */
    const char *sswitch [])             /*  Filter these options from argv   */
{
#if (defined (__UNIX__))
    int
        fork_result,
        file_handle;
    char
        pid_buffer [10];
    struct flock
        lock_file;                      /*  flock() argument block           */
#endif
    int
        argi = 0,                       /*  Input arguments iterator         */
        argo = 0;                       /*  Output arguments iterator        */
    char
        **newargv = NULL;               /*  Array of new arguments           */

    newargv = malloc (argc * sizeof (char *));
    if (newargv == NULL)
        return (-1);

    /*  Copy the arguments across, skipping any in sswitch                   */
    for (argi = argo = 0; argi < argc; argi++)
      {
        Bool
            copy_argument = TRUE;
        int
            i = 0;

        for (i = 0; sswitch != NULL && sswitch [i] != NULL; i++)
          {
            if (strcmp (argv [argi], sswitch [i]) == 0)
                copy_argument = FALSE;
          }
        if (copy_argument)
            newargv [argo++] = argv [argi];
      }

    /*  Terminate the new argument array                                     */
    newargv [argo] = NULL;

#if (defined (__UNIX__))
    /*  We recreate our process as a child of init.  The process continues   */
    /*  to exit in the background.  UNIX calls wait() for all children of    */
    /*  the init process, so the server will exit cleanly.                   */

    fork_result = fork ();
    if (fork_result < 0)                /*  < 0 is an error                  */
        return (-1);                    /*  Could not fork                   */
    else
    if (fork_result > 0)                /*  > 0 is the parent process        */
        exit (EXIT_SUCCESS);            /*  End parent process               */

    /*  We close all open file descriptors that may have been inherited      */
    /*  from the parent process.  This is to reduce the resources we use.    */

    for (file_handle = FILEHANDLE_MAX - 1; file_handle >= 0; file_handle--)
        close (file_handle);            /*  Ignore errors                    */

    /*  We move to a safe and known directory, which is supplied as an       */
    /*  argument to this function (or not, if workdir is NULL or empty).     */

    if (workdir && strused (workdir))
        chdir (workdir);

    /*  We set the umask so that new files are given mode 750 octal          */

    umask (027);                        /*  Complement of 0750               */

    /*  We set standard input and output to the null device so that any      */
    /*  functions that assume that these files are open can still work.      */

    file_handle = open ("/dev/null", O_RDWR);    /*  stdin = handle 0        */
    dup (file_handle);                           /*  stdout = handle 1       */
    dup (file_handle);                           /*  stderr = handle 2       */

    /*  We enforce a lock on the lockfile, if specified, so that only one    */
    /*  copy of the server can run at once.  We return -1 if the lock fails. */
    /*  This locking code might be better isolated into a separate package,  */
    /*  since it is not very portable between unices.                        */

    if (lockfile && strused (lockfile))
      {
        file_handle = open (lockfile, O_RDWR | O_CREAT, 0640);
        if (file_handle < 0)
            return (-1);                /*  We could not open lock file      */
        else
          {
            lock_file.l_type = F_WRLCK;
            if (fcntl (file_handle, F_SETLK, &lock_file))
                return (-1);            /*  We could not obtain a lock       */
          }
        /*  We record the server's process id in the lock file               */
        snprintf (pid_buffer, sizeof (pid_buffer), "%6d\n", getpid ());
        write   (file_handle, pid_buffer, strlen (pid_buffer));
      }

    /*  We ignore any hangup signal from the controlling TTY                 */
    signal (SIGHUP, SIG_IGN);
    return (0);                         /*  Initialisation completed ok      */

#elif (defined (__OS2__))

    /*  Start a new copy of the program up, running detached from this
     *  program.  Quote the arguments to prevent expansion because they've
     *  already been expanded once if applicable.  The program name is taken
     *  to be argv[0] due to the lack of better options, and the path will be
     *  searched to try to find it.
     *
     *  Providing the program starts successfully, this process exits,
     *  otherwise an error is returned.
     */
#   if (defined (__EMX__))

    if (spawnvp ((P_NOWAIT | P_DETACH | P_QUOTE), newargv [0], newargv) == -1)
        return -1;
    else
        exit (EXIT_SUCCESS);

#   else
#   error Do not know how to run detached program.    
#   endif 

#else
    return (0);                         /*  Nothing to do on this system     */
#endif
}


#if (defined (__WINDOWS__))

/*  handle_timer -- internal
 *
 *  This function is called by Windows when the timer goes off.  We use this
 *  to send a SIGALRM to whoever is handling signals.  (SIGALRM is actually
 *  SIGFPE, since MSVC does not know SIGALRM, and its raise() function
 *  only works with the pathetic little group of standard signals.)
 *  We call WSACancelBlockingCall(), which *should* unblock any select() or
 *  other blocking winsock call that is in progress.  If you are waiting in
 *  a select() loop, and a timer goes off, you want to go handle it right
 *  away.  Sadly, this does not work with all (any?) winsocks.  So, a word
 *  to the wise: if you use select() and timers, under Windows you should
 *  use a select() timeout that matches the level of responsiveness that
 *  you need.  (Typically 100-500ms.)
 */
static UINT                             /*  We only want a single timer to   */
    last_timer = 0;                     /*    be active at once.             */
#   if (defined (WIN32))
void FAR PASCAL handle_timer (UINT idTimer, UINT msg,
                              DWORD dw1, DWORD dw2, DWORD dw3)
#   else
void CALLBACK handle_timer (HWND hwnd, UINT msg, UINT timerid, DWORD time)
#   endif
{
    WSACancelBlockingCall ();           /*  Force "interrupted system call"  */
    raise (SIGALRM);                    /*  Simulate UNIX signal             */
    last_timer = 0;                     /*    and note that timer has gone   */
}
#endif

/*  ---------------------------------------------------------------------[<]-
    Function: process_alarm

    Synopsis: Sets a system timer to raise a SIGALRM after a specified
    interval in milliseconds.  Returns TRUE if the timer could be created
    and FALSE if there were insufficient resources, or if the system does
    not support timers.  Permits a single alarm for the current process:
    any alarm that was still pending when you called this function is
    annulled.  The implementation is system-dependent and highly
    non-portable.

    Under UNIX we use the setitimer() system function, which is clean and
    simple.

    BeOS does not support this, so we use the good old alarm() function.

    Under 16-bit Windows we use the SetTimer() call.  This does not work
    in 32-bit console applications.  Under 32-bit Windows we use the
    'multimedia' timer, which provides better resolution and does work
    in console applications.  In both these cases we cache the id of the
    last-created alarm (and kill it before each new request), to avoid
    multiple active alarms.  It is not a good idea to create too many
    concurrent timers; after 16 or so the alarms start to fail.  This is
    not supposed to happen with MM timers, but does anyway.  Under
    Windows, SIGALRM does not exist.  Since signal() only accepts one of
    a small set of fixed signals, we hijack the SIGFPE signal...  It's a
    compromise and requires that any code which expects a SIGALRM does
    not use SIGFPE.  This can be tweaked in prelude.h.

    Under OS/2 we use the alarm() function which is accurate to one
    second only.  The required accuracy of timing is not easily
    achieved, so process_alarm() rounds down to whole seconds (except if
    rounding down would give 0, in which case it will delay 1 second).
    This will probably cause problems in code applications that depends
    on sub-second timing resolution.

    Under OpenVMS 7 and later we use the setitimer() function as for
    UNIX.  Under OpenVMS 6 and earlier we use the alarm() function as
    for OS/2.  This code may be tuned to use native VMS system calls.
    ---------------------------------------------------------------------[>]-*/

Bool
process_alarm (long delay)
{
#if ((defined (__UNIX__) && !defined (__UTYPE_BEOS)) || defined (__VMS_XOPEN))
    struct itimerval
        timeout;                        /*  Timeout for setitimer            */

    /*  If the system supports interval timers, ask for a signal             */
    timeout.it_interval.tv_sec  = 0;
    timeout.it_interval.tv_usec = 0;
    timeout.it_value.tv_sec     = delay / 1000;
    timeout.it_value.tv_usec    = delay % 1000 * 1000L;
    setitimer (ITIMER_REAL, &timeout, 0);
    return (TRUE);

#elif (defined (__OS2__) || defined (__VMS__) || defined (__UTYPE_BEOS))
    /*  Since we use alarm() for our timeout, we can only time to            */
    /*  the nearest second, and alarm(0) turns off the alarm.                */
    /*  NOTE: we also have only one timer -- if alarm() is called while      */
    /*  the alarm is active, then it will be reset to the new value, and     */
    /*  only a single SIGALRM will be generated.                             */
    delay = (delay < 1000) ? 1 : (delay / 1000);
    alarm (delay);
    return (TRUE);

#elif (defined (__WINDOWS__))
#   if (defined (WIN32))
#   pragma comment (lib, "winmm")       /*  Link-in multimedia library       */
    /*  The multimedia timer gives the best accuracy, and works in console   */
    /*  applications                                                         */
    int rc;
    if (last_timer)
        __try {
            rc = timeKillEvent (last_timer);
        }
        __except (1) {
            coprintf ("timeKillEvent %d failed", last_timer);
        }
    __try {
        last_timer = timeSetEvent (delay, 50, handle_timer, 0, TIME_ONESHOT);
    }
    __except (1) {
        coprintf ("timeSetEvent %ld failed", delay);
    }
    return (TRUE);

#   else
    /*  But the normal Windows timer will do if we're in 16 bits             */
    if (last_timer)
        KillTimer ((HWND) NULL, last_timer);

    last_timer = SetTimer ((HWND) NULL, 0, (UINT) delay, handle_timer);
    return (TRUE);
#   endif

#else
    return (FALSE);                     /*  No timers - function failed      */
#endif
}


/*  ---------------------------------------------------------------------[<]-
    Function: process_esc

    Synopsis: Escapes a directory string so that process_create() can handle
    it correctly.  If you pass a command to process_create with a directory
    name that contains spaces, it will assume that the spaces delimit the
    command from its arguments.  For instance, under Windows 95, the filename
    "C:\Program Files\Myprog.exe" will be incorrectly treated as a program
    called "C:\Program" with arguments "Files\Myprog.exe".  This function
    replaces spaces by the escape character (0x1B).  You cannot use this
    value in a filename and expect process_create() to work correctly.  On
    an EBCDIC system, the escape character (0x27) is also used.  If the
    dest argument is NULL, allocates a string using mem_alloc() and returns
    that.  Otherwise copies into the dest string and returns that.  If the
    src string is NULL, returns an empty string.
    ---------------------------------------------------------------------[>]-*/

char *
process_esc (char *dest, const char *src)
{
#if (defined (__EBCDIC__))
#   define ESC_CHAR   0x27
#else
#   define ESC_CHAR   0x1B
#endif
    /*  Copy to dest, allocate if necessary                                  */
    if (dest != src)
      {
        xstrcpy_debug ();
        dest = xstrcpy (dest, src, NULL);
      }
    strconvch (dest, ' ', ESC_CHAR);
    return (dest);
}


/*  ---------------------------------------------------------------------[<]-
    Function: process_unesc

    Synopsis: Does the reverse translaction to process_esc().
    ---------------------------------------------------------------------[>]-*/

char *
process_unesc (char *dest, const char *src)
{
    /*  Copy to dest, allocate if necessary                                  */
    if (dest != src)
      {
        xstrcpy_debug ();
        dest = xstrcpy (dest, src, NULL);
      }
    strconvch (dest, ESC_CHAR, ' ');
    return (dest);
}


/*  ---------------------------------------------------------------------[<]-
    Function: process_priority

    Synopsis: Sets process priority as specified, to one of PRIORITY_LOW,
    PRIORITY_NORMAL, or PRIORITY_HIGH.  Currently has an effect only under
    Windows NT/95.  Returns 0 if okay, -1 if there was an error.
    ---------------------------------------------------------------------[>]-*/

int
process_priority (int priority)
{
#if (defined (WIN32))
    int
        class;

    if (priority == PRIORITY_HIGH)
        class = HIGH_PRIORITY_CLASS;
    else
    if (priority == PRIORITY_LOW)
        class = IDLE_PRIORITY_CLASS;
    else
        class = NORMAL_PRIORITY_CLASS;

    return (SetPriorityClass (GetCurrentProcess (), class));
#else
    return (0);
#endif
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -