125184Sjkh/* $NetBSD: popen.c,v 1.2 2010/05/06 18:53:17 christos Exp $ */ 225184Sjkh 348662Speter/* 425184Sjkh * Copyright (c) 1988, 1993, 1994 525184Sjkh * The Regents of the University of California. All rights reserved. 625184Sjkh * 725184Sjkh * This code is derived from software written by Ken Arnold and 825184Sjkh * published in UNIX Review, Vol. 6, No. 8. 925184Sjkh * 1025184Sjkh * Redistribution and use in source and binary forms, with or without 1125184Sjkh * modification, are permitted provided that the following conditions 1225184Sjkh * are met: 1325184Sjkh * 1. Redistributions of source code must retain the above copyright 1425184Sjkh * notice, this list of conditions and the following disclaimer. 1525184Sjkh * 2. Redistributions in binary form must reproduce the above copyright 1625184Sjkh * notice, this list of conditions and the following disclaimer in the 1725184Sjkh * documentation and/or other materials provided with the distribution. 1825184Sjkh * 3. All advertising materials mentioning features or use of this software 1925184Sjkh * must display the following acknowledgement: 2025184Sjkh * This product includes software developed by the University of 2125184Sjkh * California, Berkeley and its contributors. 2225184Sjkh * 2325184Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2425184Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2525184Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2625184Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2725184Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2840006Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2940006Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3040006Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3140006Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3240006Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3340006Sphk * SUCH DAMAGE. 3442621Shm * 3542621Shm */ 3642621Shm 3742621Shm/* this came out of the ftpd sources; it's been modified to avoid the 3842621Shm * globbing stuff since we don't need it. also execvp instead of execv. 3942627Sjoerg */ 4042627Sjoerg 4142627Sjoerg#include <sys/cdefs.h> 4242627Sjoerg#ifndef lint 4342627Sjoerg#if 0 4442627Sjoergstatic sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; 4542627Sjoergstatic char rcsid[] = "Id: popen.c,v 1.6 2003/02/16 04:40:01 vixie Exp"; 4642627Sjoerg#else 4742627Sjoerg__RCSID("$NetBSD: popen.c,v 1.2 2010/05/06 18:53:17 christos Exp $"); 4842627Sjoerg#endif 4942627Sjoerg#endif /* not lint */ 5042627Sjoerg 5142627Sjoerg#include "cron.h" 5242627Sjoerg 5325184Sjkh#define MAX_ARGV 100 5448662Speter#define MAX_GARGV 1000 5548662Speter 5648662Speter/* 5725184Sjkh * Special version of popen which avoids call to shell. This ensures noone 5833682Sbrian * may create a pipe to a hidden program as a side effect of a list or dir 5948662Speter * command. 6025184Sjkh */ 6125184Sjkhstatic PID_T *pids; 6225184Sjkhstatic long fds; 6325184Sjkh 6425184SjkhFILE * 6548662Spetercron_popen(char *program, const char *type, struct passwd *pw) { 6625184Sjkh char *cp; 6725184Sjkh FILE *iop; 6825184Sjkh int argc, pdes[2]; 6925184Sjkh PID_T pid; 7025184Sjkh char *argv[MAX_ARGV]; 7125184Sjkh 7225184Sjkh if ((*type != 'r' && *type != 'w') || type[1] != '\0') 7325184Sjkh return (NULL); 7448662Speter 7525184Sjkh if (!pids) { 7625184Sjkh size_t len; 7725184Sjkh if ((fds = sysconf(_SC_OPEN_MAX)) <= 0) 7825184Sjkh return (NULL); 7925184Sjkh len = fds * sizeof(*pids); 8025184Sjkh if ((pids = malloc(len)) == NULL) 8125184Sjkh return (NULL); 8225184Sjkh (void)memset(pids, 0, len); 8325184Sjkh } 8448662Speter if (pipe(pdes) < 0) 8525184Sjkh return (NULL); 8648662Speter 8748662Speter /* break up string into pieces */ 8848662Speter for (argc = 0, cp = program; argc < MAX_ARGV - 1; cp = NULL) 8948662Speter if (!(argv[argc++] = strtok(cp, " \t\n"))) 9025184Sjkh break; 9129300Sdanny argv[MAX_ARGV-1] = NULL; 9229300Sdanny 9329300Sdanny switch (pid = vfork()) { 9429300Sdanny case -1: /* error */ 9532382Salex (void)close(pdes[0]); 9632382Salex (void)close(pdes[1]); 9732382Salex return (NULL); 9829300Sdanny /* NOTREACHED */ 9929300Sdanny case 0: /* child */ 10029300Sdanny if (pw) { 10129300Sdanny if (setsid() == -1) 10241077Speter warn("setsid() failed for %s", pw->pw_name); 10329300Sdanny#ifdef LOGIN_CAP 10429300Sdanny if (setusercontext(0, pw, pw->pw_uid, LOGIN_SETALL) < 0) 10529300Sdanny { 10629300Sdanny warn("setusercontext() failed for %s", 10729300Sdanny pw->pw_name); 10829300Sdanny _exit(ERROR_EXIT); 10929300Sdanny } 11029300Sdanny#else 11129300Sdanny if (setgid(pw->pw_gid) < 0 || 11245542Sdes initgroups(pw->pw_name, pw->pw_gid) < 0) { 11345542Sdes warn("unable to set groups for %s", 11445542Sdes pw->pw_name); 11545542Sdes _exit(ERROR_EXIT); 11645542Sdes } 11745622Sbrian#if (defined(BSD)) && (BSD >= 199103) 11844992Sbrian if (setlogin(pw->pw_name) < 0) { 11944992Sbrian warn("setlogin() failed for %s", 12044992Sbrian pw->pw_name); 12144992Sbrian _exit(ERROR_EXIT); 12244992Sbrian } 12344992Sbrian#endif /* BSD */ 12444992Sbrian if (setuid(pw->pw_uid)) { 12544992Sbrian warn("unable to set uid for %s", pw->pw_name); 12644992Sbrian _exit(ERROR_EXIT); 12744992Sbrian } 12844992Sbrian#endif /* LOGIN_CAP */ 12944992Sbrian } 13029300Sdanny if (*type == 'r') { 13133337Salex if (pdes[1] != STDOUT) { 13233337Salex (void)dup2(pdes[1], STDOUT); 13333149Salex (void)close(pdes[1]); 13433149Salex } 13533149Salex (void)dup2(STDOUT, STDERR); /* stderr too! */ 13633149Salex (void)close(pdes[0]); 13729300Sdanny } else { 13825184Sjkh if (pdes[0] != STDIN) { 13925184Sjkh (void)dup2(pdes[0], STDIN); 14040006Sphk (void)close(pdes[0]); 14140006Sphk } 14240006Sphk (void)close(pdes[1]); 14340006Sphk } 14440006Sphk (void)execvp(argv[0], argv); 14529300Sdanny _exit(ERROR_EXIT); 14629300Sdanny } 14725184Sjkh 14825184Sjkh /* parent; assume fdopen can't fail... */ 14925184Sjkh if (*type == 'r') { 15025184Sjkh iop = fdopen(pdes[0], type); 15125184Sjkh (void)close(pdes[1]); 15225184Sjkh } else { 15325184Sjkh iop = fdopen(pdes[1], type); 15425184Sjkh (void)close(pdes[0]); 15525184Sjkh } 15625184Sjkh pids[fileno(iop)] = pid; 15725184Sjkh 15825184Sjkh return (iop); 15925184Sjkh} 16025184Sjkh 16127218Spstint 16227218Spstcron_pclose(FILE *iop) { 16347755Sbde int fdes; 16427218Spst PID_T pid; 16527218Spst WAIT_T status; 16645096Simp sigset_t sset, osset; 16745096Simp 16847755Sbde /* 16947755Sbde * pclose returns -1 if stream is not associated with a 17045096Simp * `popened' command, or, if already `pclosed'. 17145096Simp */ 17239267Sjkoshy if (pids == 0 || pids[fdes = fileno(iop)] == 0) 17339267Sjkoshy return (-1); 17447755Sbde (void)fclose(iop); 17539267Sjkoshy (void)sigemptyset(&sset); 17639267Sjkoshy (void)sigaddset(&sset, SIGINT); 17725184Sjkh (void)sigaddset(&sset, SIGQUIT); 17825365Sjkh (void)sigaddset(&sset, SIGHUP); 17947755Sbde (void)sigprocmask(SIG_BLOCK, &sset, &osset); 18025184Sjkh while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 18125184Sjkh continue; 18233439Sguido (void)sigprocmask(SIG_SETMASK, &osset, NULL); 18333439Sguido pids[fdes] = 0; 18447755Sbde if (pid < 0) 18533439Sguido return (pid); 18633439Sguido if (WIFEXITED(status)) 18733439Sguido return (WEXITSTATUS(status)); 18833439Sguido else 18947755Sbde return WTERMSIG(status); 19033439Sguido} 19133439Sguido