Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  vstream_popen.c

  Sprache: C
 

/*++
/* NAME
/* vstream_popen 3
/* SUMMARY
/* open stream to child process
/* SYNOPSIS
/* #include <vstream.h>
/*
/* VSTREAM *vstream_popen(flags, key, value, ...)
/* int flags;
/* int key;
/*
/* int vstream_pclose(stream)
/* VSTREAM *stream;
/* DESCRIPTION
/* vstream_popen() opens a one-way or two-way stream to a user-specified
/* command, which is executed by a child process. The \fIflags\fR
/* argument is as with vstream_fopen(). The child's standard input and
/* standard output are redirected to the stream, which is based on a
/* socketpair or other suitable local IPC. vstream_popen() takes a list
/* of macros with zero or more arguments, terminated by
/* CA_VSTREAM_POPEN_END.  The following is a listing of macros
/* with the expected argument type.
/* .RS
/* .IP "CA_VSTREAM_POPEN_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_VSTREAM_POPEN_COMMAND or VSTREAM_POPEN_ARGV must be specified.
/* .IP "CA_VSTREAM_POPEN_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_VSTREAM_POPEN_COMMAND or VSTREAM_POPEN_ARGV must be specified.
/* See also the CA_VSTREAM_POPEN_SHELL attribute below.
/* .IP "CA_VSTREAM_POPEN_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_VSTREAM_POPEN_EXPORT(char **)"
/* This argument is passed to clean_env().
/* Null-terminated array of names of environment parameters
/* that can be exported. By default, everything is exported.
/* .IP "CA_VSTREAM_POPEN_UID(uid_t)"
/* The user ID to execute the command as. The user ID must be non-zero.
/* .IP "CA_VSTREAM_POPEN_GID(gid_t)"
/* The group ID to execute the command as. The group ID must be non-zero.
/* .IP "CA_VSTREAM_POPEN_SHELL(const char *)"
/* The shell to use when executing the command specified with
/* CA_VSTREAM_POPEN_COMMAND. This shell is invoked regardless of the
/* command content.
/* .IP "CA_VSTREAM_POPEN_WAITPID_FN(pid_t (*)(pid_t, WAIT_STATUS_T *, int))"
/* waitpid()-like function to reap the child exit status when
/* vstream_pclose() is called.
/* .RE
/* .PP
/* vstream_pclose() closes the named stream and returns the child
/* exit status. It is an error to specify a stream that was not
/* returned by vstream_popen() or that is no longer open.
/* DIAGNOSTICS
/* Panics: interface violations. Fatal errors: out of memory.
/*
/* vstream_popen() returns a null pointer in case of trouble.
/* The nature of the problem is specified via the \fIerrno\fR
/* global variable.
/*
/* vstream_pclose() returns -1 in case of trouble.
/* The nature of the problem is specified via the \fIerrno\fR
/* global variable.
/* SEE ALSO
/* vstream(3) light-weight buffered I/O
/* BUGS
/* The interface, stolen from popen()/pclose(), ignores errors
/* returned when the stream is closed, and does not distinguish
/* between exit status codes and kill signals.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* 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 <unistd.h>
#include <stdlib.h>
#include <errno.h>
#ifdef USE_PATHS_H
#include <paths.h>
#endif
#include <syslog.h>

/* Utility library. */

#include <msg.h>
#include <exec_command.h>
#include <vstream.h>
#include <argv.h>
#include <set_ugid.h>
#include <clean_env.h>
#include <iostuff.h>

/* Application-specific. */

typedef struct VSTREAM_POPEN_ARGS {
    char  **argv;
    char   *command;
    uid_t   uid;
    gid_t   gid;
    int     privileged;
    char  **env;
    char  **export;
    char   *shell;
    VSTREAM_WAITPID_FN waitpid_fn;
} VSTREAM_POPEN_ARGS;

/* vstream_parse_args - get arguments from variadic list */

static void vstream_parse_args(VSTREAM_POPEN_ARGS *args, va_list ap)
{
    const char *myname = "vstream_parse_args";
    int     key;

    /*
     * First, set the default values (on all non-zero entries)
     */

    args->argv = 0;
    args->command = 0;
    args->uid = 0;
    args->gid = 0;
    args->privileged = 0;
    args->env = 0;
    args->export = 0;
    args->shell = 0;
    args->waitpid_fn = 0;

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

    while ((key = va_arg(ap, int)) != VSTREAM_POPEN_END) {
 switch (key) {
 case VSTREAM_POPEN_ARGV:
     if (args->command != 0)
  msg_panic("%s: got VSTREAM_POPEN_ARGV and VSTREAM_POPEN_COMMAND", myname);
     args->argv = va_arg(ap, char **);
     break;
 case VSTREAM_POPEN_COMMAND:
     if (args->argv != 0)
  msg_panic("%s: got VSTREAM_POPEN_ARGV and VSTREAM_POPEN_COMMAND", myname);
     args->command = va_arg(ap, char *);
     break;
 case VSTREAM_POPEN_UID:
     args->privileged = 1;
     args->uid = va_arg(ap, uid_t);
     break;
 case VSTREAM_POPEN_GID:
     args->privileged = 1;
     args->gid = va_arg(ap, gid_t);
     break;
 case VSTREAM_POPEN_ENV:
     args->env = va_arg(ap, char **);
     break;
 case VSTREAM_POPEN_EXPORT:
     args->export = va_arg(ap, char **);
     break;
 case VSTREAM_POPEN_SHELL:
     args->shell = va_arg(ap, char *);
     break;
 case VSTREAM_POPEN_WAITPID_FN:
     args->waitpid_fn = va_arg(ap, VSTREAM_WAITPID_FN);
     break;
 default:
     msg_panic("%s: unknown key: %d", myname, key);
 }
    }

    if (args->command == 0 && args->argv == 0)
 msg_panic("%s: missing VSTREAM_POPEN_ARGV or VSTREAM_POPEN_COMMAND", myname);
    if (args->privileged != 0 && args->uid == 0)
 msg_panic("%s: privileged uid", myname);
    if (args->privileged != 0 && args->gid == 0)
 msg_panic("%s: privileged gid", myname);
}

/* vstream_popen - open stream to child process */

VSTREAM *vstream_popen(int flags,...)
{
    const char *myname = "vstream_popen";
    VSTREAM_POPEN_ARGS args;
    va_list ap;
    VSTREAM *stream;
    int     sockfd[2];
    int     pid;
    int     fd;
    ARGV   *argv;
    char  **cpp;

    va_start(ap, flags);
    vstream_parse_args(&args, ap);
    va_end(ap);

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

    if (duplex_pipe(sockfd) < 0)
 return (0);

    switch (pid = fork()) {
    case -1:     /* error */
 (void) close(sockfd[0]);
 (void) close(sockfd[1]);
 return (0);
    case 0:     /* child */
 (void) msg_cleanup((MSG_CLEANUP_FN) 0);
 if (close(sockfd[1]))
     msg_warn("close: %m");
 for (fd = 0; fd < 2; fd++)
     if (sockfd[0] != fd)
  if (DUP2(sockfd[0], fd) < 0)
      msg_fatal("dup2: %m");
 if (sockfd[0] >= 2 && close(sockfd[0]))
     msg_warn("close: %m");

 /*
  * Don't try to become someone else unless the user specified it.
 */

 if (args.privileged)
     set_ugid(args.uid, args.gid);

 /*
  * 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 */
    default:     /* parent */
 if (close(sockfd[0]))
     msg_warn("close: %m");
 stream = vstream_fdopen(sockfd[1], flags);
 stream->waitpid_fn = args.waitpid_fn;
 stream->pid = pid;
 return (stream);
    }
}

/* vstream_pclose - close stream to child process */

int     vstream_pclose(VSTREAM *stream)
{
    pid_t   saved_pid = stream->pid;
    VSTREAM_WAITPID_FN saved_waitpid_fn = stream->waitpid_fn;
    pid_t   pid;
    WAIT_STATUS_T wait_status;

    /*
     * Close the pipe. Don't trigger an alarm in vstream_fclose().
     */

    if (saved_pid == 0)
 msg_panic("vstream_pclose: stream has no process");
    stream->pid = 0;
    vstream_fclose(stream);

    /*
     * Reap the child exit status.
     */

    do {
 if (saved_waitpid_fn != 0)
     pid = saved_waitpid_fn(saved_pid, &wait_status, 0);
 else
     pid = waitpid(saved_pid, &wait_status, 0);
    } while (pid == -1 && errno == EINTR);
    return (pid == -1 ? -1 :
     WIFSIGNALED(wait_status) ? WTERMSIG(wait_status) :
     WEXITSTATUS(wait_status));
}

#ifdef TEST

#include <fcntl.h>
#include <vstring.h>
#include <vstring_vstream.h>

 /*
  * Test program. Run a command and copy lines one by one.
  */

int     main(int argc, char **argv)
{
    VSTRING *buf = vstring_alloc(100);
    VSTREAM *stream;
    int     status;

    /*
     * Sanity check.
     */

    if (argc < 2)
 msg_fatal("usage: %s 'command'", argv[0]);

    /*
     * Open stream to child process.
     */

    if ((stream = vstream_popen(O_RDWR,
    VSTREAM_POPEN_ARGV, argv + 1,
    VSTREAM_POPEN_END)) == 0)
 msg_fatal("vstream_popen: %m");

    /*
     * Copy loop, one line at a time.
     */

    while (vstring_fgets(buf, stream) != 0) {
 if (vstream_fwrite(VSTREAM_OUT, vstring_str(buf), VSTRING_LEN(buf))
     != VSTRING_LEN(buf))
     msg_fatal("vstream_fwrite: %m");
 if (vstream_fflush(VSTREAM_OUT) != 0)
     msg_fatal("vstream_fflush: %m");
 if (vstring_fgets(buf, VSTREAM_IN) == 0)
     break;
 if (vstream_fwrite(stream, vstring_str(buf), VSTRING_LEN(buf))
     != VSTRING_LEN(buf))
     msg_fatal("vstream_fwrite: %m");
    }

    /*
     * Cleanup.
     */

    vstring_free(buf);
    if ((status = vstream_pclose(stream)) != 0)
 msg_warn("exit status: %d", status);

    exit(status);
}

#endif

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

¤ Dauer der Verarbeitung: 0.19 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=141584
#Domains=738142