4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 * Module: zones_exec.c
32 * Description: Provide "zones" execution interface for install
37 * z_ExecCmdArray - Execute a Unix command and return results and status
38 * _zexec - run a command with arguments on a specified zone
39 * _zexec_init_template - used by _zexec to establish contracts
40 * _z_zone_exec - Execute a Unix command in a specified zone and return results
41 * z_ExecCmdList - Execute a Unix command and return results and status
53 #include <sys/types.h>
54 #include <sys/param.h>
65 #include <libcontract.h>
66 #include <sys/contract/process.h>
74 #include "instzones_lib.h"
75 #include "zones_strings.h"
82 * Library Function Prototypes
86 * Local Function Prototypes
90 * global internal (private) declarations
94 * *****************************************************************************
95 * global external (public) functions
96 * *****************************************************************************
100 * Name: z_ExecCmdArray
101 * Synopsis: Execute Unix command and return results
102 * Description: Execute a Unix command and return results and status
104 * r_status - [RO, *RW] - (int *)
105 * Return (exit) status from Unix command:
106 * == -1 : child terminated with a signal
107 * != -1 : lower 8-bit value child passed to exit()
108 * r_results - [RO, *RW] - (char **)
109 * Any output generated by the Unix command to stdout
111 * == (char *)NULL if no output generated
112 * a_inputFile - [RO, *RO] - (char *)
113 * Pointer to character string representing file to be
114 * used as "standard input" for the command.
115 * == (char *)NULL to use "/dev/null" as standard input
116 * a_cmd - [RO, *RO] - (char *)
117 * Pointer to character string representing the full path
118 * of the Unix command to execute
119 * char **a_args - [RO, *RO] - (char **)
120 * List of character strings representing the arguments
121 * to be passed to the Unix command. The list must be
122 * terminated with an element that is (char *)NULL
124 * == 0 - Command executed
125 * Look at r_status for results of Unix command
126 * != 0 - problems executing command
127 * r_status and r_results have no meaning;
128 * r_status will be -1
129 * r_results will be NULL
130 * NOTE: Any results returned is placed in new storage for the
131 * calling method. The caller must use 'free' to dispose
132 * of the storage once the results are no longer needed.
133 * NOTE: If 0 is returned, 'r_status' must be queried to
134 * determine the results of the Unix command.
135 * NOTE: The system "errno" value from immediately after waitpid() call
136 * is preserved for the calling method to use to determine
137 * the system reason why the operation failed.
141 z_ExecCmdArray(int *r_status
, char **r_results
,
142 char *a_inputFile
, char *a_cmd
, char **a_args
)
147 int ipipe
[2] = {0, 0};
154 /* entry assertions */
156 assert(r_status
!= NULL
);
157 assert(a_cmd
!= NULL
);
158 assert(*a_cmd
!= '\0');
159 assert(a_args
!= NULL
);
161 /* reset return results buffer pointer */
163 if (r_results
!= (char **)NULL
) {
164 *r_results
= (char *)NULL
;
170 * See if command exists
173 if (access(a_cmd
, F_OK
|X_OK
) != 0) {
178 * See if input file exists
181 if (a_inputFile
!= (char *)NULL
) {
182 stdinfile
= open(a_inputFile
, O_RDONLY
);
184 stdinfile
= open("/dev/null", O_RDONLY
); /* stdin = /dev/null */
192 * Create a pipe to be used to capture the command output
195 if (pipe(ipipe
) != 0) {
196 (void) close(stdinfile
);
201 bufferSize
= PIPE_BUFFER_INCREMENT
;
203 buffer
= calloc(1, bufferSize
);
204 if (buffer
== (char *)NULL
) {
205 (void) close(stdinfile
);
209 /* flush standard i/o before creating new process */
211 (void) fflush(stderr
);
212 (void) fflush(stdout
);
215 * create new process to execute command in;
216 * vfork() is being used to avoid duplicating the parents
217 * memory space - this means that the child process may
218 * not modify any of the parents memory including the
219 * standard i/o descriptors - all the child can do is
220 * adjust interrupts and open files as a prelude to a
228 * This is the forked (child) process ======================
233 /* reset any signals to default */
235 for (i
= 0; i
< NSIG
; i
++) {
236 (void) sigset(i
, SIG_DFL
);
239 /* assign stdin, stdout, stderr as appropriate */
241 (void) dup2(stdinfile
, STDIN_FILENO
);
242 (void) close(ipipe
[0]); /* close out pipe reader side */
243 (void) dup2(ipipe
[1], STDOUT_FILENO
);
244 (void) dup2(ipipe
[1], STDERR_FILENO
);
246 /* Close all open files except standard i/o */
250 /* execute target executable */
252 (void) execvp(a_cmd
, a_args
);
253 perror(a_cmd
); /* Emit error msg - ends up in callers buffer */
255 } else if (pid
== -1) {
256 _z_program_error(ERR_FORK
, strerror(errno
));
262 * This is the forking (parent) process ====================
265 (void) close(stdinfile
);
266 (void) close(ipipe
[1]); /* Close write side of pipe */
269 * Spin reading data from the child into the buffer - when the read eofs
270 * the child has exited
276 /* read as much child data as there is available buffer space */
278 bytesRead
= read(ipipe
[0], buffer
+ bufferIndex
,
279 bufferSize
- bufferIndex
);
281 /* break out of read loop if end-of-file encountered */
283 if (bytesRead
== 0) {
287 /* if error, continue if recoverable, else break out of loop */
289 if (bytesRead
== -1) {
290 /* try again: EAGAIN - insufficient resources */
292 if (errno
== EAGAIN
) {
296 /* try again: EINTR - interrupted system call */
298 if (errno
== EINTR
) {
302 /* break out of loop - error not recoverable */
306 /* at least 1 byte read: expand buffer if at end */
308 bufferIndex
+= bytesRead
;
309 if (bufferIndex
>= bufferSize
) {
310 buffer
= realloc(buffer
,
311 bufferSize
+= PIPE_BUFFER_INCREMENT
);
312 (void) memset(buffer
+ bufferIndex
, 0,
313 bufferSize
- bufferIndex
);
317 (void) close(ipipe
[0]); /* Close read side of pipe */
319 /* Get subprocess exit status */
322 resultPid
= waitpid(pid
, &status
, 0L);
323 lerrno
= (resultPid
== -1 ? errno
: 0);
325 /* break loop if child process status reaped */
327 if (resultPid
!= -1) {
331 /* break loop if not interrupted out of waitpid */
333 if (errno
!= EINTR
) {
339 * If the child process terminated due to a call to exit(), then
340 * set results equal to the 8-bit exit status of the child process;
341 * otherwise, set the exit status to "-1" indicating that the child
342 * exited via a signal.
345 *r_status
= WIFEXITED(status
) ? WEXITSTATUS(status
) : -1;
347 /* return appropriate output */
350 /* No contents in output buffer - discard */
352 } else if (r_results
== (char **)NULL
) {
353 /* Not requested to return results - discard */
356 /* have output and request to return: pass to calling method */
361 return (resultPid
== -1 ? -1 : 0);
366 * Description: run a command with arguments on a specified zone
367 * Arguments: a_zoneName - pointer to string representing the name of the zone
368 * to execute the specified command in
369 * a_path - pointer to string representing the full path *in the
370 * non-global zone named by a_zoneName* of the Unix command
372 * a_argv[] - Pointer to array of character strings representing
373 * the arguments to be passed to the Unix command. The list
374 * must be termianted with an element that is (char *)NULL
375 * NOTE: a_argv[0] is the "command name" passed to the command
377 * This function must be treated like a call to exec()
378 * If the exec() is successful, the thread of control is
379 * NOT returned, and the process will exit when completed.
380 * If this function returns, it means the exec() could not
381 * be done, or another fatal error occurred.
385 _zexec(const char *a_zoneName
, const char *a_path
, char *a_argv
[])
389 char **new_env
= { NULL
};
392 /* entry assertions */
394 assert(a_zoneName
!= NULL
);
395 assert(*a_zoneName
!= '\0');
396 assert(a_path
!= NULL
);
397 assert(*a_path
!= '\0');
399 /* establish locale settings */
401 (void) setlocale(LC_ALL
, "");
402 (void) textdomain(TEXT_DOMAIN
);
404 /* can only be invoked from within the global zone */
406 if (getzoneid() != GLOBAL_ZONEID
) {
407 _z_program_error(ERR_ZEXEC_NOT_IN_GZ
, a_zoneName
);
411 if (strcmp(a_zoneName
, GLOBAL_ZONENAME
) == 0) {
412 _z_program_error(ERR_ZEXEC_GZUSED
, a_zoneName
);
416 /* get the state of the specified zone */
418 if (zone_get_state((char *)a_zoneName
, &st
) != Z_OK
) {
419 _z_program_error(ERR_ZEXEC_BADZONE
, a_zoneName
);
423 if (st
< ZONE_STATE_INSTALLED
) {
424 _z_program_error(ERR_ZEXEC_BADSTATE
, a_zoneName
,
429 if (st
!= ZONE_STATE_RUNNING
&& st
!= ZONE_STATE_MOUNTED
) {
430 _z_program_error(ERR_ZEXEC_NOTRUNNING
, a_zoneName
,
436 * In both console and non-console cases, we require all privs.
437 * In the console case, because we may need to startup zoneadmd.
438 * In the non-console case in order to do zone_enter(2), zonept()
441 * Future work: this solution is temporary. Ultimately, we need to
442 * move to a flexible system which allows the global admin to
443 * designate that a particular user can zlogin (and probably zlogin
444 * -C) to a particular zone. This all-root business we have now is
448 if ((privset
= priv_allocset()) == NULL
) {
449 _z_program_error(ERR_ZEXEC_PRIV_ALLOCSET
, a_zoneName
,
454 if (getppriv(PRIV_EFFECTIVE
, privset
) != 0) {
455 _z_program_error(ERR_ZEXEC_GETPPRIV
, a_zoneName
,
457 priv_freeset(privset
);
461 if (priv_isfullset(privset
) == B_FALSE
) {
462 _z_program_error(ERR_ZEXEC_PRIVS
, a_zoneName
);
463 priv_freeset(privset
);
466 priv_freeset(privset
);
468 if ((zoneid
= getzoneidbyname(a_zoneName
)) == -1) {
469 _z_program_error(ERR_ZEXEC_NOZONEID
, a_zoneName
,
474 if ((new_env
= _zexec_prep_env()) == NULL
) {
475 _z_program_error(ERR_ZEXEC_ASSEMBLE
, a_zoneName
);
480 * In case any of stdin, stdout or stderr are streams,
481 * anchor them to prevent malicious I_POPs.
483 * Future work: use pipes to entirely eliminate FD leakage
487 (void) ioctl(STDIN_FILENO
, I_ANCHOR
);
488 (void) ioctl(STDOUT_FILENO
, I_ANCHOR
);
489 (void) ioctl(STDERR_FILENO
, I_ANCHOR
);
491 if (zone_enter(zoneid
) == -1) {
494 _z_program_error(ERR_ZEXEC_ZONEENTER
, a_zoneName
,
497 if (lerrno
== EFAULT
) {
498 _z_program_error(ERR_ZEXEC_EFAULT
, a_zoneName
);
506 (void) execve(a_path
, &a_argv
[0], new_env
);
508 _z_program_error(ERR_ZEXEC_EXECFAILURE
, a_zoneName
, strerror(errno
));
514 * Name: _zexec_init_template
515 * Description: used by _zexec to establish contracts
519 _zexec_init_template(void)
524 fd
= open64(CTFS_ROOT
"/process/template", O_RDWR
);
530 * zlogin doesn't do anything with the contract.
531 * Deliver no events, don't inherit, and allow it to be orphaned.
533 err
|= ct_tmpl_set_critical(fd
, 0);
534 err
|= ct_tmpl_set_informative(fd
, 0);
535 err
|= ct_pr_tmpl_set_fatal(fd
, CT_PR_EV_HWERR
);
536 err
|= ct_pr_tmpl_set_param(fd
, CT_PR_PGRPONLY
| CT_PR_REGENT
);
537 if (err
|| ct_tmpl_activate(fd
)) {
546 * Helper routine for _zexec_prep_env below.
549 _zexec_add_env(char *name
, char *value
)
551 size_t sz
= strlen(name
) + strlen(value
) + 1;
554 if ((str
= malloc(sz
)) == NULL
)
557 (void) snprintf(str
, sz
, "%s%s", name
, value
);
562 * Prepare envp array for exec'd process.
568 char **new_env
, *estr
;
569 char *term
= getenv("TERM");
571 size
++; /* for $PATH */
576 * In failsafe mode we set $HOME
581 * In failsafe mode we set $SHELL, since login won't be around to do it.
585 if ((new_env
= malloc(sizeof (char *) * size
)) == NULL
)
588 if ((estr
= _zexec_add_env("PATH=", ZONE_DEF_PATH
)) == NULL
) {
595 if ((estr
= _zexec_add_env("TERM=", term
)) == NULL
) {
602 if ((estr
= _zexec_add_env("HOME=", "/")) == NULL
) {
608 if ((estr
= _zexec_add_env("SHELL=", ZONE_FAILSAFESHELL
)) == NULL
) {
621 * Description: Execute a Unix command in a specified zone and return results
623 * r_status - [RO, *RW] - (int *)
624 * Return (exit) status from Unix command:
625 * == -1 : child terminated with a signal
626 * != -1 : lower 8-bit value child passed to exit()
627 * r_results - [RO, *RW] - (char **)
628 * Any output generated by the Unix command to stdout
630 * == (char *)NULL if no output generated
631 * a_inputFile - [RO, *RO] - (char *)
632 * Pointer to character string representing file to be
633 * used as "standard input" for the command.
634 * == (char *)NULL to use "/dev/null" as standard input
635 * a_path - [RO, *RO] - (char *)
636 * Pointer to character string representing the full path
637 * *in the non-global zone named by a_zoneName*of the Unix
638 * command to be executed
639 * char **a_args - [RO, *RO] - (char **)
640 * List of character strings representing the arguments
641 * to be passed to the Unix command.
642 * NOTE: The list must be terminated with an element that
643 * ----- is (char *)NULL
644 * NOTE: a_argv[0] is the "command name" passed to the
645 * ----- command executed in the specified non-global zone
646 * a_zoneName - pointer to string representing the name of the zone
647 * to execute the specified command in
648 * a_fds - Pointer to array of integers representing file
649 * descriptors to remain open during the call - all
650 * file descriptors above STDERR_FILENO not in this
651 * list will be closed.
653 * == 0 - Command executed
654 * Look at r_status for results of Unix command
655 * != 0 - problems executing command
656 * r_status and r_results have no meaning;
657 * r_status will be -1
658 * r_results will be NULL
659 * The return (exit) code from the specified Unix command
660 * Special return codes:
661 * -1 : failure to exec process
662 * -2 : could not create contract for greenline
664 * -4 : could not open stdin source file
665 * -5 : error from 'waitpid' other than EINTR
666 * -6 : zones are not supported
667 * -7 : interrupt received
668 * NOTE: All file descriptores other than 0, 1 and 2 are closed except
669 * for those file descriptors listed in the a_fds array.
673 _z_zone_exec(int *r_status
, char **r_results
, char *a_inputFile
,
674 char *a_path
, char *a_argv
[], const char *a_zoneName
, int *a_fds
)
676 struct sigaction nact
;
677 struct sigaction oact
;
683 int ipipe
[2] = {0, 0};
691 void (*funcSighup
)();
692 void (*funcSigint
)();
694 /* entry assertions */
696 assert(a_path
!= (char *)NULL
);
697 assert(*a_path
!= '\0');
698 assert(a_argv
!= (char **)NULL
);
699 assert(a_argv
[0] != (char *)NULL
);
700 assert(*a_argv
[0] != '\0');
701 assert(a_zoneName
!= (char *)NULL
);
704 * if requested to execute in current zone name, directly execute
707 thisZoneName
= z_get_zonename();
708 status
= (strcmp(a_zoneName
, thisZoneName
) == 0);
710 /* entry debugging info */
712 _z_echoDebug(DBG_ZONE_EXEC_CMD_ENTER
, a_path
, a_zoneName
, thisZoneName
);
713 (void) free(thisZoneName
);
714 for (n
= 0; a_argv
[n
]; n
++) {
715 _z_echoDebug(DBG_ARG
, n
, a_argv
[n
]);
718 /* if this zone, just exec the command directly */
721 return (z_ExecCmdArray(r_status
, r_results
, a_inputFile
,
725 /* reset return results buffer pointer */
727 if (r_results
!= (char **)NULL
) {
728 *r_results
= (char *)NULL
;
731 *r_status
= -1; /* -1 : failure to exec process */
733 /* if zones are not implemented, return TRUE */
735 if (!z_zones_are_implemented()) {
736 return (-6); /* -6 : zones are not supported */
739 if ((tmpl_fd
= _zexec_init_template()) == -1) {
740 _z_program_error(ERR_CANNOT_CREATE_CONTRACT
, strerror(errno
));
741 return (-2); /* -2 : cannot create greenline contract */
745 * See if input file exists
748 if (a_inputFile
!= (char *)NULL
) {
749 stdinfile
= open(a_inputFile
, O_RDONLY
);
751 stdinfile
= open("/dev/null", O_RDONLY
); /* stdin = /dev/null */
755 return (-4); /* -4 : could not open stdin source file */
759 * Create a pipe to be used to capture the command output
762 if (pipe(ipipe
) != 0) {
763 (void) close(stdinfile
);
767 bufferSize
= PIPE_BUFFER_INCREMENT
;
769 buffer
= calloc(1, bufferSize
);
770 if (buffer
== (char *)NULL
) {
771 (void) close(stdinfile
);
775 /* flush standard i/o before creating new process */
777 (void) fflush(stderr
);
778 (void) fflush(stdout
);
781 * hold SIGINT/SIGHUP signals and reset signal received counter;
782 * after the fork1() the parent and child need to setup their respective
783 * interrupt handling and release the hold on the signals
786 (void) sighold(SIGINT
);
787 (void) sighold(SIGHUP
);
789 _z_global_data
._z_SigReceived
= 0; /* no signals received */
792 * fork off a new process to execute command in;
793 * fork1() is used instead of vfork() so the child process can
794 * perform operations that would modify the parent process if
802 * *************************************************************
804 * *************************************************************
807 (void) ct_tmpl_clear(tmpl_fd
);
808 (void) close(tmpl_fd
);
810 _z_program_error(ERR_FORK
, strerror(errno
));
812 /* release hold on signals */
813 (void) sigrelse(SIGHUP
);
814 (void) sigrelse(SIGINT
);
816 return (-3); /* -3 : fork() failed */
819 if (child_pid
== 0) {
823 * *************************************************************
824 * This is the forked (child) process
825 * *************************************************************
828 (void) ct_tmpl_clear(tmpl_fd
);
829 (void) close(tmpl_fd
);
831 /* reset any signals to default */
833 for (i
= 0; i
< NSIG
; i
++) {
834 (void) sigset(i
, SIG_DFL
);
837 /* assign stdin, stdout, stderr as appropriate */
839 (void) dup2(stdinfile
, STDIN_FILENO
);
840 (void) close(ipipe
[0]); /* close out pipe reader side */
841 (void) dup2(ipipe
[1], STDOUT_FILENO
);
842 (void) dup2(ipipe
[1], STDERR_FILENO
);
845 * close all file descriptors not in the a_fds list
848 (void) fdwalk(&_z_close_file_descriptors
, (void *)a_fds
);
850 /* release all held signals */
852 (void) sigrelse(SIGHUP
);
853 (void) sigrelse(SIGINT
);
855 /* execute command in the specified non-global zone */
857 _exit(_zexec(a_zoneName
, a_path
, a_argv
));
861 * *********************************************************************
862 * This is the forking (parent) process
863 * *********************************************************************
866 /* register child process i.d. so signal handlers can pass signal on */
868 _z_global_data
._z_ChildProcessId
= child_pid
;
871 * setup signal handlers for SIGINT and SIGHUP and release hold
874 /* hook SIGINT to _z_sig_trap() */
876 nact
.sa_handler
= _z_sig_trap
;
877 nact
.sa_flags
= SA_RESTART
;
878 (void) sigemptyset(&nact
.sa_mask
);
880 if (sigaction(SIGINT
, &nact
, &oact
) < 0) {
881 funcSigint
= SIG_DFL
;
883 funcSigint
= oact
.sa_handler
;
886 /* hook SIGHUP to _z_sig_trap() */
888 nact
.sa_handler
= _z_sig_trap
;
889 nact
.sa_flags
= SA_RESTART
;
890 (void) sigemptyset(&nact
.sa_mask
);
892 if (sigaction(SIGHUP
, &nact
, &oact
) < 0) {
893 funcSighup
= SIG_DFL
;
895 funcSighup
= oact
.sa_handler
;
898 /* release hold on signals */
900 (void) sigrelse(SIGHUP
);
901 (void) sigrelse(SIGINT
);
903 (void) ct_tmpl_clear(tmpl_fd
);
904 (void) close(tmpl_fd
);
906 (void) close(stdinfile
);
907 (void) close(ipipe
[1]); /* Close write side of pipe */
910 * Spin reading data from the child into the buffer - when the read eofs
911 * the child has exited
917 /* read as much child data as there is available buffer space */
919 bytesRead
= read(ipipe
[0], buffer
+ bufferIndex
,
920 bufferSize
- bufferIndex
);
922 /* break out of read loop if end-of-file encountered */
924 if (bytesRead
== 0) {
928 /* if error, continue if recoverable, else break out of loop */
930 if (bytesRead
== -1) {
931 /* try again: EAGAIN - insufficient resources */
933 if (errno
== EAGAIN
) {
937 /* try again: EINTR - interrupted system call */
939 if (errno
== EINTR
) {
943 /* break out of loop - error not recoverable */
947 /* at least 1 byte read: expand buffer if at end */
949 bufferIndex
+= bytesRead
;
950 if (bufferIndex
>= bufferSize
) {
951 buffer
= realloc(buffer
,
952 bufferSize
+= PIPE_BUFFER_INCREMENT
);
953 (void) memset(buffer
+ bufferIndex
, 0,
954 bufferSize
- bufferIndex
);
958 (void) close(ipipe
[0]); /* Close read side of pipe */
961 * wait for the process to exit, reap child exit status
965 result_pid
= waitpid(child_pid
, &status
, 0L);
966 lerrno
= (result_pid
== -1 ? errno
: 0);
968 /* break loop if child process status reaped */
970 if (result_pid
!= -1) {
974 /* break loop if not interrupted out of waitpid */
976 if (errno
!= EINTR
) {
981 /* reset child process i.d. so signal handlers do not pass signals on */
983 _z_global_data
._z_ChildProcessId
= -1;
986 * If the child process terminated due to a call to exit(), then
987 * set results equal to the 8-bit exit status of the child process;
988 * otherwise, set the exit status to "-1" indicating that the child
989 * exited via a signal.
992 if (WIFEXITED(status
)) {
993 *r_status
= WEXITSTATUS(status
);
994 if ((_z_global_data
._z_SigReceived
!= 0) && (*r_status
== 0)) {
998 *r_status
= -1; /* -1 : failure to exec process */
1001 /* determine proper exit code */
1003 if (result_pid
== -1) {
1004 exit_no
= -5; /* -5 : error from 'waitpid' other than EINTR */
1005 } else if (_z_global_data
._z_SigReceived
!= 0) {
1006 exit_no
= -7; /* -7 : interrupt received */
1011 /* return appropriate output */
1014 /* No contents in output buffer - discard */
1016 } else if (r_results
== (char **)NULL
) {
1017 /* Not requested to return results - discard */
1020 /* have output and request to return: pass to calling method */
1021 *r_results
= buffer
;
1025 * reset signal handlers
1030 nact
.sa_handler
= funcSigint
;
1031 nact
.sa_flags
= SA_RESTART
;
1032 (void) sigemptyset(&nact
.sa_mask
);
1034 (void) sigaction(SIGINT
, &nact
, (struct sigaction
*)NULL
);
1038 nact
.sa_handler
= funcSighup
;
1039 nact
.sa_flags
= SA_RESTART
;
1040 (void) sigemptyset(&nact
.sa_mask
);
1042 (void) sigaction(SIGHUP
, &nact
, (struct sigaction
*)NULL
);
1045 * if signal received during command execution, interrupt
1049 if (_z_global_data
._z_SigReceived
!= 0) {
1050 (void) kill(getpid(), SIGINT
);
1053 /* set errno and return */
1061 * Name: z_ExecCmdList
1062 * Synopsis: Execute Unix command and return results
1063 * Description: Execute a Unix command and return results and status
1065 * r_status - [RO, *RW] - (int *)
1066 * Return (exit) status from Unix command
1067 * r_results - [RO, *RW] - (char **)
1068 * Any output generated by the Unix command to stdout
1070 * == (char *)NULL if no output generated
1071 * a_inputFile - [RO, *RO] - (char *)
1072 * Pointer to character string representing file to be
1073 * used as "standard input" for the command.
1074 * == (char *)NULL to use "/dev/null" as standard input
1075 * a_cmd - [RO, *RO] - (char *)
1076 * Pointer to character string representing the full path
1077 * of the Unix command to execute
1079 * Zero or more arguments to the Unix command
1080 * The argument list must be ended with (void *)NULL
1082 * == 0 - Command executed
1083 * Look at r_status for results of Unix command
1084 * != 0 - problems executing command
1085 * r_status and r_results have no meaning
1086 * NOTE: Any results returned is placed in new storage for the
1087 * calling method. The caller must use 'free' to dispose
1088 * of the storage once the results are no longer needed.
1089 * NOTE: If LU_SUCCESS is returned, 'r_status' must be queried to
1090 * determine the results of the Unix command.
1095 z_ExecCmdList(int *r_status
, char **r_results
,
1096 char *a_inputFile
, char *a_cmd
, ...)
1098 va_list ap
; /* references variable argument list */
1099 char *array
[MAX_EXEC_CMD_ARGS
+1];
1103 * Create argument array for exec system call
1106 bzero(array
, sizeof (array
));
1108 va_start(ap
, a_cmd
); /* Begin variable argument processing */
1110 for (argno
= 0; argno
< MAX_EXEC_CMD_ARGS
; argno
++) {
1111 array
[argno
] = va_arg(ap
, char *);
1112 if (array
[argno
] == (char *)NULL
) {
1118 return (z_ExecCmdArray(r_status
, r_results
, a_inputFile
,