system.c revision f9f6ed06923c6f348695de4d5185b4013adc4b6b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#include "lint.h"
#include "mtlib.h"
#include <signal.h>
#include <stdlib.h>
#include <wait.h>
#include <unistd.h>
#include <memory.h>
#include <thread.h>
#include <pthread.h>
#include <errno.h>
#include <synch.h>
#include <spawn.h>
#include "libc.h"
extern const char **_environ;
/*
* Things needed by the cancellation cleanup handler.
*/
typedef struct {
} cleanup_t;
/*
* Daemon thread whose sole function is to reap an abandoned child.
*/
void *
{
int cancel_state;
break;
}
return (NULL);
}
/*
* Cancellation cleanup handler.
* If we were cancelled in waitpid(), create a daemon thread to
* reap our abandoned child. No other thread can do this for us.
* It would be better if there were a system call to disinherit
* a child process (give it to init, just as though we exited).
*/
static void
{
(void) thr_create(NULL, 0,
THR_DAEMON, NULL);
}
if (--sys_count == 0) { /* leaving system() */
/*
* There are no remaining threads in system(), so
* restore the SIGINT and SIGQUIT signal actions.
*/
}
}
int
{
pid_t w;
int status;
int error;
const char *shpath;
char *argv[4];
static const char *shell = "sh";
return (0);
/* exec for user */
return (0);
/* exec for group */
return (0);
return (0);
}
return (1);
}
/*
* Initialize the posix_spawn() attributes structure.
*
* The setting of POSIX_SPAWN_WAITPID_NP ensures that no
* wait-for-multiple wait() operation will reap our child
* and that the child will not be automatically reaped due
* to the disposition of SIGCHLD being set to be ignored.
* Only a specific wait for the specific pid will be able
* to reap the child. Since no other thread knows the pid
* of our child, this should be safe enough.
*
* The POSIX_SPAWN_NOEXECERR_NP flag tells posix_spawn() not
* to fail if the shell cannot be executed, but rather cause
* a child to be created that simply performs _exit(127).
* This is in order to satisfy the Posix requirement on system():
* The system function shall behave as if a child process were
* created using fork(), and the child process invoked the sh
* utility using execl(). If some error prevents the command
* language interpreter from executing after the child process
* is created, the return value from system() shall be as if
* the command language interpreter had terminated using
* exit(127) or _exit(127).
*/
if (error == 0)
/*
* The POSIX spec for system() requires us to block SIGCHLD,
* the rationale being that the process's signal handler for
* SIGCHLD, if any, should not be called when our child exits.
* This doesn't work for a multithreaded process because some
* other thread could receive the SIGCHLD.
*
* The above setting of POSIX_SPAWN_NOSIGCHLD_NP ensures that no
* SIGCHLD signal will be posted for our child when it exits, so
* we don't have to block SIGCHLD to meet the intent of the spec.
* We block SIGCHLD anyway, just because the spec requires it.
*/
(void) sigemptyset(&mask);
/*
* Tell posix_spawn() to restore the signal mask in the child.
*/
if (error == 0)
/*
* We are required to set the disposition of SIGINT and SIGQUIT
* to be ignored for the duration of the system() operation.
*
* We allow more than one thread to call system() concurrently by
* keeping a count of such threads. The signal actions are set
* to SIG_IGN when the first thread calls system(). They are
* restored in cleanup() when the last thread exits system().
*
* However, system() is still MT-unsafe because sigaction() has
* a process-wide effect and some other thread may also be
* setting the signal actions for SIGINT or SIGQUIT.
*/
if (sys_count++ == 0) {
}
/*
* If SIGINT and SIGQUIT were not already SIG_IGN, tell
* posix_spawn() to make them SIG_DFL in the child,
* else leave them as SIG_IGN in the child.
*/
(void) sigemptyset(&mask);
if (error == 0)
if (error == 0)
(void) posix_spawnattr_destroy(&attr);
if (error) {
status = -1;
} else {
/*
* system() is a cancellation point and so is waitpid().
*/
do {
if (w == -1)
status = -1;
}
return (status);
}