Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  spawn_command.c

  Sprache: C
 

/*++
/* NAME
/* spawn_command 3
/* SUMMARY
/* run external command
/* SYNOPSIS
/* #include <spawn_command.h>
/*
/* WAIT_STATUS_T spawn_command(key, ...)
/* int key;
/* AUXILIARY FUNCTIONS
/* get_spawn_args(
/* struct spawn_args *args,
/* int key,
/* va_list ap)
/* DESCRIPTION
/* spawn_command() runs a command in a child process and returns
/* the command exit status.
/*
/* Arguments:
/* .IP key
/* spawn_command() takes a list of macros with arguments,
/* terminated by CA_SPAWN_CMD_END which has no arguments. The
/* following is a listing of macros and expected argument
/* types.
/* .RS
/* .IP "CA_SPAWN_CMD_COMMAND(const char *)"
/* Specifies the command to execute as a string. The string is
/* passed to the shell when it contains shell meta characters
/* or when it appears to be a shell built-in command, otherwise
/* the command is executed without invoking a shell.
/* One of CA_SPAWN_CMD_COMMAND or CA_SPAWN_CMD_ARGV must be specified.
/* See also the SPAWN_CMD_SHELL attribute below.
/* .IP "CA_SPAWN_CMD_ARGV(char **)"
/* The command is specified as an argument vector. This vector is
/* passed without further inspection to the \fIexecvp\fR() routine.
/* One of CA_SPAWN_CMD_COMMAND or CA_SPAWN_CMD_ARGV must be specified.
/* .IP "CA_SPAWN_CMD_ENV(char **)"
/* Additional environment information, in the form of a null-terminated
/* list of name, value, name, value, ... elements. By default only the
/* command search path is initialized to _PATH_DEFPATH.
/* .IP "CA_SPAWN_CMD_EXPORT(char **)"
/* Null-terminated array of names of environment parameters that can
/* be exported. By default, everything is exported.
/* .IP "CA_SPAWN_CMD_STDIN(int)"
/* .IP "CA_SPAWN_CMD_STDOUT(int)"
/* .IP "CA_SPAWN_CMD_STDERR(int)"
/* Each of these specifies I/O redirection of one of the standard file
/* descriptors for the command.
/* .IP "CA_SPAWN_CMD_UID(uid_t)"
/* The user ID to execute the command as. The value -1 is reserved
/* and cannot be specified.
/* .IP "CA_SPAWN_CMD_GID(gid_t)"
/* The group ID to execute the command as. The value -1 is reserved
/* and cannot be specified.
/* .IP "CA_SPAWN_CMD_TIME_LIMIT(int)"
/* The amount of time in seconds the command is allowed to run before
/* it is terminated with SIGKILL. The default is no time limit.
/* .IP "CA_SPAWN_CMD_SHELL(const char *)"
/* The shell to use when executing the command specified with
/* CA_SPAWN_CMD_COMMAND. This shell is invoked regardless of the
/* command content.
/* .RE
/* DIAGNOSTICS
/* Panic: interface violations (for example, a missing command).
/*
/* Fatal error: fork() failure, other system call failures.
/*
/* spawn_command() returns the exit status as defined by wait(2).
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* SEE ALSO
/* exec_command(3) execute command
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#ifdef USE_PATHS_H
#include <paths.h>
#endif
#include <syslog.h>

/* Utility library. */

#include <msg.h>
#include <timed_wait.h>
#include <set_ugid.h>
#include <set_eugid.h>
#include <argv.h>
#include <spawn_command.h>
#include <exec_command.h>
#include <clean_env.h>

/* Application-specific. */

/* get_spawn_args - capture the variadic argument list */

void    get_spawn_args(struct spawn_args *args, int init_key, va_list ap)
{
    const char *myname = "get_spawn_args";
    int     key;

    /*
     * First, set the default values.
     */

    args->argv = 0;
    args->command = 0;
    args->stdin_fd = -1;
    args->stdout_fd = -1;
    args->stderr_fd = -1;
    args->uid = (uid_t) - 1;
    args->gid = (gid_t) - 1;
    args->env = 0;
    args->export = 0;
    args->shell = 0;
    args->time_limit = 0;

    /*
     * Then, override the defaults with user-supplied inputs.
     */

    for (key = init_key; key != SPAWN_CMD_END; key = va_arg(ap, int)) {
 switch (key) {
 case SPAWN_CMD_ARGV:
     if (args->command)
  msg_panic("%s: specify SPAWN_CMD_ARGV or SPAWN_CMD_COMMAND",
     myname);
     args->argv = va_arg(ap, char **);
     break;
 case SPAWN_CMD_COMMAND:
     if (args->argv)
  msg_panic("%s: specify SPAWN_CMD_ARGV or SPAWN_CMD_COMMAND",
     myname);
     args->command = va_arg(ap, char *);
     break;
 case SPAWN_CMD_STDIN:
     args->stdin_fd = va_arg(ap, int);
     break;
 case SPAWN_CMD_STDOUT:
     args->stdout_fd = va_arg(ap, int);
     break;
 case SPAWN_CMD_STDERR:
     args->stderr_fd = va_arg(ap, int);
     break;
 case SPAWN_CMD_UID:
     args->uid = va_arg(ap, uid_t);
     if (args->uid == (uid_t) (-1))
  msg_panic("spawn_command: request with reserved user ID: -1");
     break;
 case SPAWN_CMD_GID:
     args->gid = va_arg(ap, gid_t);
     if (args->gid == (gid_t) (-1))
  msg_panic("spawn_command: request with reserved group ID: -1");
     break;
 case SPAWN_CMD_TIME_LIMIT:
     args->time_limit = va_arg(ap, int);
     break;
 case SPAWN_CMD_ENV:
     args->env = va_arg(ap, char **);
     break;
 case SPAWN_CMD_EXPORT:
     args->export = va_arg(ap, char **);
     break;
 case SPAWN_CMD_SHELL:
     args->shell = va_arg(ap, char *);
     break;
 default:
     msg_panic("%s: unknown key: %d", myname, key);
 }
    }
    if (args->command == 0 && args->argv == 0)
 msg_panic("%s: missing SPAWN_CMD_ARGV or SPAWN_CMD_COMMAND", myname);
    if (args->command == 0 && args->shell != 0)
 msg_panic("%s: SPAWN_CMD_ARGV cannot be used with SPAWN_CMD_SHELL",
    myname);
}

/* spawn_command - execute command with extreme prejudice */

WAIT_STATUS_T spawn_command(int key,...)
{
    const char *myname = "spawn_comand";
    va_list ap;
    pid_t   pid;
    WAIT_STATUS_T wait_status;
    struct spawn_args args;
    char  **cpp;
    ARGV   *argv;
    int     err;

    /*
     * Process the variadic argument list. This also does sanity checks on
     * what data the caller is passing to us.
     */

    va_start(ap, key);
    get_spawn_args(&args, key, ap);
    va_end(ap);

    /*
     * For convenience...
     */

    if (args.command == 0)
 args.command = args.argv[0];

    /*
     * Spawn off a child process and irrevocably change privilege to the
     * user. This includes revoking all rights on open files (via the close
     * on exec flag). If we cannot run the command now, try again some time
     * later.
     */

    switch (pid = fork()) {

 /*
  * Error. Instead of trying again right now, back off, give the
  * system a chance to recover, and try again later.
 */

    case -1:
 msg_fatal("fork: %m");

 /*
  * Child. Run the child in a separate process group so that the
  * parent can kill not just the child but also its offspring.
 */

    case 0:
 if (args.uid != (uid_t) - 1 || args.gid != (gid_t) - 1)
     set_ugid(args.uid, args.gid);
 if (setsid() < 0)
     msg_warn("child: setsid: %m");

 /*
  * Pipe plumbing.
 */

 if ((args.stdin_fd >= 0 && DUP2(args.stdin_fd, STDIN_FILENO) < 0)
  || (args.stdout_fd >= 0 && DUP2(args.stdout_fd, STDOUT_FILENO) < 0)
 || (args.stderr_fd >= 0 && DUP2(args.stderr_fd, STDERR_FILENO) < 0))
     msg_fatal("%s: dup2: %m", myname);

 /*
  * Environment plumbing. Always reset the command search path. XXX
  * That should probably be done by clean_env().
 */

 if (args.export)
     clean_env(args.export);
 if (setenv("PATH", _PATH_DEFPATH, 1))
     msg_fatal("%s: setenv: %m", myname);
 if (args.env)
     for (cpp = args.env; *cpp; cpp += 2)
  if (setenv(cpp[0], cpp[1], 1))
      msg_fatal("setenv: %m");

 /*
  * Process plumbing. If possible, avoid running a shell.
 */

 closelog();
 if (args.argv) {
     execvp(args.argv[0], args.argv);
     msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
 } else if (args.shell && *args.shell) {
     argv = argv_split(args.shell, CHARS_SPACE);
     argv_add(argv, args.command, (char *) 0);
     argv_terminate(argv);
     execvp(argv->argv[0], argv->argv);
     msg_fatal("%s: execvp %s: %m", myname, argv->argv[0]);
 } else {
     exec_command(args.command);
 }
 /* NOTREACHED */

 /*
  * Parent.
 */

    default:

 /*
  * Be prepared for the situation that the child does not terminate.
  * Make sure that the child terminates before the parent attempts to
  * retrieve its exit status, otherwise the parent could become stuck,
  * and the mail system would eventually run out of exec daemons. Do a
  * thorough job, and kill not just the child process but also its
  * offspring.
 */

 if ((err = timed_waitpid(pid, &wait_status, 0, args.time_limit)) < 0
     && errno == ETIMEDOUT) {
     uid_t   saved_euid = geteuid();
     gid_t   saved_egid = getegid();

     msg_warn("%s: process id %lu: command time limit exceeded",
       args.command, (unsigned long) pid);
     set_eugid(args.uid, args.gid);
     if (kill(-pid, SIGKILL) < 0)
  msg_warn("parent: kill: %m");
     set_eugid(saved_euid, saved_egid);
     err = waitpid(pid, &wait_status, 0);
 }
 if (err < 0)
     msg_fatal("wait: %m");
 return (wait_status);
    }
}

Messung V0.5 in Prozent
C=72 H=94 G=83

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002