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

📄 sflproc.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sflproc.c
    Title:      Process control functions
    Package:    Standard Function Library (SFL)

    Written:    1996/09/09  iMatix SFL project team <sfl@imatix.com>
    Revised:    2000/04/01

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sfllist.h"                    /*  Linked-list functions            */
#include "sflmem.h"                     /*  Memory-handling functions        */
#include "sflstr.h"                     /*  String-handling functions        */
#include "sflfile.h"                    /*  File access functions            */
#include "sflnode.h"                    /*  Memory node functions            */
#include "sfldir.h"                     /*  Directory access functions       */
#include "sflcons.h"                    /*  Prototypes for functions         */
#include "sflsymb.h"                    /*  Symbol table handling            */
#include "sfltok.h"                     /*  Token-handling functions         */
#include "sflenv.h"                     /*  Environment handling functions   */
#include "sflprint.h"                   /*  snprintf functions               */

#include "sflproc.h"                    /*  Prototypes for functions         */
#include "sflprocx.h"                   /*  Extra sflproc functions          */

/*  Global variables                                                         */

int  process_errno = 0;                 /*  Last process exit code           */
Bool process_compatible = TRUE;         /*  Try to be compatible             */


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

    Synopsis: Creates a subprocess and returns a PROCESS identifying the new
    process.  Optionally redirects standard input, output, error file handles
    to supplied file handles, changes working directory, and environment.
    In some operating systems can also optinally change the root directory
    (chroot()), and the uid/gid with which the new process runs.
    All information required to start the new process is specified in a
    PROCESS_DATA structure.  Where elements are not specified, they remain the
    same as the current process.  The following elements can be specified
    in the PROCESS_DATA structure:
    <Table>
    filename      File to execute, can include arguments if argv is NULL.
    argv_[]       List of arguments; argv [0] is filename; ends in a NULL.
    path          Search path (environments PATH is used if NULL).
    shell         Shell to use if useshell is TRUE (default is OS specific)
    searchext     Array of extensions to search when looking for filename
    searchpath    Flag: TRUE indicates path should be searched for filename
    useshell      Flag: TRUE indicates program should be started via a shell
    createdaemon  Flag: TRUE indicates a (separate) daemon should be started
    wait          Flag: TRUE indicates wait for process to finish
    delay         Amount of time to wait around for errors to happen (unix)
    rootdir       Root directory for new process (chroot()) if not NULL
    workdir       Working directory; if NULL, remains in current directory.
    in            File handle to use for standard input; -2 = no redirection.
    out           File handle to use for standard output; -2 = no redirection.
    err           File handle to use for standard error; -2 = no redirection.
    no_handles    Number of file handles to pass to child process (default: 3)
    envv_[]       Whole environment for new process; if NULL current env used
    envadd        Strings to add into current environment (if envv NULL).
    envrm         Keys to remove from current environment (if envv NULL).
    username      user name under which to run process
    groupname     groupname associated with user name
    password      required if calling process is not privileged
    </Table>
    If argv is NULL, parses the filename argument into words delimited by
    whitespace and builds the necessary argv table automatically.  Use this
    feature to execute a command with arguments, specified as one string.
    To search for the program in the path set searchpath to TRUE, and
    optionally supply a path to search.  To run shell builtins set useshell
    to TRUE.
    The envv list consists of strings in the form "name=value", ending in a
    NULL pointer.  If the envv argument is null, the environment of the
    current process is passed, with additions from envadd (if not NULL),
    and the keys listed in envrm removed (if not NULL).  If envv is not null
    then the envv environment is used as is.
    The child process may optionally start in a new root directory and with
    a different user/group (if supported by the operating system).  If rootdir,
    workdir, user, and group are all non null, then they are processed in the
    order: rootdir, workdir, group, user, to ensure all changes take place.
    Note that in this instance workdir is relative to the new root directory.
    Under DOS, Windows, and OS/2, the rootdir may be used to specify a change
    to a new drive letter (processed by _chdir() or _chdir2()).
    If the child command detects an error
    at startup, it may exit with an error status.  The sleep allows this
    error to be collected by calling process_status() after this call.  
    Returns child process id, or 0 if there was an error.  The PROCESS_DATA
    structure contains the following fields used for output:
    <Table>
    pid           Process identifier (as returned by function)
    returncode    Return code from sub process (only set if wait is TRUE)
    error         Code indicating error that occured (like libc errno)
    </Table>
    Under VMS, the filename must have been defined as a command before the
    calling process was started; the path is disregarded.
    Under Windows and OS/2 processing of the #! line is emulated, and the
    interpreter mentioned in the #! line will be invoked on the script.
    Under OS/2 the filename can be the name of a CMD script, and this will
    be run with the interpreter specified in the first line (EXTPROC line,
    or "'/'*!" line; or failing that with the default command interpreter.
    ---------------------------------------------------------------------[>]-*/

PROCESS
process_create_full (PROCESS_DATA *procinfo)
{
    /*  Implementation note: due to the size of this function, and the       */
    /*  sizeable differences between operating systems supported, the        */
    /*  implementation of this function for each operating system is in      */
    /*  a different file, and the appropriate one is included here.          */

    /*  WARNING: do not put any code here, otherwise it will prevent the     */
    /*  implementations from declaring variables.                            */

#if   (defined (__UNIX__))
#   include "sflprocu.imp"              /*  Unix implementation              */
#elif (defined (__OS2__))
#   include "sflproco.imp"              /*  OS/2 implementation              */
#elif (defined (WIN32))
#   include "sflprocw.imp"              /*  Windows (32-bit) implementation  */
#elif (defined (__VMS__))
#   include "sflprocv.imp"              /*  VMS implementation               */
#else
    return ((PROCESS) 0);               /*  Not supported on this system     */
#endif
}

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

    Synopsis: Creates a subprocess and returns a PROCESS identifying the new
    process.  Optionally directs standard input, output, and error streams
    to specified devices.  The caller can also specify environment symbols
    that the subprocess can access.  Accepts these arguments:
    <Table>
    filename    File to execute; if bare filename, searches PATH.
    argv_[]     List of arguments; argv [0] is filename; ends in a NULL.
    workdir     Working directory; if NULL, remains in current directory.
    std_in      Device to use for standard input; NULL = no redirection.
    std_out     Device to use for standard output; NULL = no redirection.
    std_err     Device to use for standard error; NULL = no redirection.
    envs_[]     List of environment symbols to define, or NULL.
    </Table>
    If argv is NULL, parses the filename argument into words delimited by
    whitespace and builds the necessary argv table automatically.  Use this
    feature to execute a command with arguments, specified as one string.
    The envv list consists of strings in the form "name=value", ending in a
    NULL pointer.  If the envv argument is null, the environment of the
    current process is passed.  Otherwise the envv environment is used.
    If the child command detects an error
    at startup, it may exit with an error status.  The sleep allows this
    error to be collected by calling process_status() after this call.  
    Returns child process id, or 0 if there was an error.
    Under VMS, the filename must have been defined as a command before the
    calling process was started; the path is disregarded.
    Under OS/2 the filename can be the name of a CMD script, and this will
    be run with the interpreter specified in the first line (EXTPROC line,
    or "'/'*!" line; or failing that with the default command interpreter.
    Under Unix, Windows, and OS/2 this function is implemented using the
    process_create_full() function.

    Known bugs: when parsing filename argument into words, does not handle
    quotes in any special way; "this text" is 2 words, '"this' and 'text"'.
    You should have passed the filename through process_esc() before adding
    any optional arguments.
    ---------------------------------------------------------------------[>]-*/

PROCESS
process_create (
    const char *filename,               /*  Name of file to execute          */
    char *argv [],                      /*  Arguments for process, or NULL   */
    const char *workdir,                /*  Working directory, or NULL       */
    const char *std_in,                 /*  Stdin device, or NULL            */
    const char *std_out,                /*  Stdout device, or NULL           */
    const char *std_err,                /*  Stderr device, or NULL           */
    char *envv [],                      /*  Environment variables, or NULL   */
    Bool  wait                          /*  Wait for process to end          */
)
{
#if (defined (__UNIX__) || defined (__OS2__) || defined (WIN32))
    PROCESS_DATA
        procinfo = PROCESS_DATA_INIT;
    PROCESS
        process = NULL_PROCESS;

    ASSERT (filename);
    if (!filename)
        return (NULL_PROCESS);

    /*  Set up information to start the new process                          */
    procinfo.filename = filename;
    procinfo.argv     = argv;
    procinfo.workdir  = workdir;
    procinfo.envv     = envv;
    procinfo.wait     = wait;

    /*  process_setinfo handles:
     *  1.  Determining if the path can be searched
     *  2.  Determining if root privileges should be preserved (if applicable)
     *  3.  Redirecting IO streams (if required)
     */
    if (process_setinfo (&procinfo, std_in, std_out, TRUE, std_err, FALSE) == 0)
      {
        process = process_create_full (&procinfo);
        process_close_io (&procinfo);
        /*  Stuff value into errno, to emulate old behaviour                 */
        errno = procinfo.error;
      }
    return (process);

#elif (defined (__VMS__))
    PROCESS
        process;                        /*  Our created process handle       */
    char
        *curdir,                        /*  Current directory                */
        *clean_filename,                /*  Unescaped filename               */
        *full_filename = NULL,
        *full_std_in   = NULL,
        *full_std_out  = NULL;
    qbyte
        process_flags;                  /*  Process creation flags           */
    int
        argn,                           /*  Argument number                  */
        rc;                             /*  Return code from lib$spawn       */
    Bool
        rebuilt_argv = FALSE;           /*  Did we rebuild argv[]?           */

    VMS_STRING (command_dsc, "");       /*  Define string descriptors        */
    VMS_STRING (std_in_dsc,  "");
    VMS_STRING (std_out_dsc, "");

    /*  If argv[] array was not supplied, build it now from filename         */
    if (!argv)
      {
        argv = tok_split (filename);
        filename = argv [0];
        rebuilt_argv = TRUE;
      }
    /*  If filename contains a path or extension, disregard them             */
    clean_filename = strrchr (filename, '/');
    if (clean_filename)
        clean_filename++;
    else
        clean_filename = (char *) filename;
    if (strchr (clean_filename, '.'))
       *strchr (clean_filename, '.') = '\0';

    /*  Rebuild full command from filename and arguments                     */
    full_filename = mem_alloc (tok_text_size ((char **) argv)
                               + strlen (clean_filename) + 1);
    strcpy (full_filename, clean_filename);
    for (argn = 1; argv [argn]; argn++)
        xstrcat (full_filename, " ", argv [argn], NULL);

    /*  Free argument table if we allocated it dynamically here              */
    if (rebuilt_argv)
        tok_free (argv);

    command_dsc.value  = full_filename;
    command_dsc.length = strlen (full_filename);

    /*  Prepare full names for stdin and stdout                              */
    curdir = get_curdir ();
    if (std_in)
      {
        if (strchr (std_in, '/'))       /*  If already with path, use as is  */
            full_std_in = mem_strdup (std_in);
        else
          {
            xstrcpy_debug ();
            full_std_in = xstrcpy (NULL, curdir, "/", std_in, NULL);
          }
        translate_to_vms  (full_std_in);
        std_in_dsc.value = full_std_in;
      }
    if (std_out)
      {
        if (strchr (std_out, '/'))      /*  If already with path, use as is  */
            full_std_out = mem_strdup (std_out);
        else
          {
            xstrcpy_debug ();
            full_std_out = xstrcpy (NULL, curdir, "/", std_out, NULL);
          }
        translate_to_vms   (full_std_out);
        std_out_dsc.value = full_std_out;
      }
    std_in_dsc.length  = std_in?  strlen (std_in_dsc.value): 0;
    std_out_dsc.length = std_out? strlen (std_out_dsc.value): 0;

    /*  If requested, change to working directory                            */
    if (workdir)
        chdir (workdir);

    /*  Prepare process flags                                                */
    if (wait)
        process_flags = 0;
    else
        process_flags = 1;              /*  Bit 1 = don't wait for child     */

    process = mem_alloc (sizeof (PROC_HANDLE));
    process-> id     = 0;
    process-> status = 0;               /*  Completion status                */

/*  char *envv [],  */                  /*  Environment variables, or NULL   */

    rc = lib$spawn (
        &command_dsc,                   /*  Command to run                   */
        std_in?  &std_in_dsc: NULL,     /*  Stdin descriptor                 */
        std_out? &std_out_dsc: NULL,    /*  Stdout+stderr                    */
        &process_flags,                 /*  Options for new process          */
        &NULL,                          /*  Process name -- generated        */
        &process-> id,                  /*  Returned process ID              */
        &process-> status);

    if (workdir)                        /*  Switch back to original dir      */
        chdir (curdir);
    mem_free (curdir);

    mem_strfree (&full_filename);       /*  Deallocate various buffers,      */
    mem_strfree (&full_std_in);         /*    if they were used              */
    mem_strfree (&full_std_out);        /*                                   */

    /*  Return process ID.  If we waited for completion, the process id      */
    /*  is always NULL.                                                      */
    if (rc != 1)                        /*  Process failed with error        */
      {
        process_close (process);
        process = NULL;
      }
    else
    if (wait)                           /*  Finished with process            */
        process_close (process);

    return (process);

#else
    return ((PROCESS) 0);               /*  Not supported on this system     */
#endif
}


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

    Synopsis: Accepts a pointer to a PROC_INFO block, and resets the fields in
    this block to default values as specified below (other fields are not
    changed):
    <Table>
    searchpath    True unless filename already contains a slash
    in            Std_in filename, or NULL

⌨️ 快捷键说明

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