/*===========================================================================* * * * sflprocx.imp - * * * * Copyright (c) 1991-2003 iMatix Corporation * * * * ------------------ GPL Licensed Source Code ------------------ * * iMatix makes this software available under the GNU General * * Public License (GPL) license for open source projects. For * * details of the GPL license please see www.gnu.org or read the * * file license.gpl provided in this package. * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public * * License along with this program in the file 'license.gpl'; if * * not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * * * * You can also license this software under iMatix's General Terms * * of Business (GTB) for commercial projects. If you have not * * explicitly licensed this software under the iMatix GTB you may * * only use it under the terms of the GNU General Public License. * * * * For more information, send an email to info@imatix.com. * * -------------------------------------------------------------- * *===========================================================================*/ /* Implementation core of the SFL process_create_full() function, used by all system-dependent implementations. We need to construct the name of the program to run, and an argv array containing all arguments, where argv[0] is the name of the program. The actual program is calculated in various ways, using this precedence: 1. If the useshell flag is TRUE, the program is the specified shell or the default shell is none is specified. The shell name may itself contain arguments that come before the program to run. 2. If the program is directly executable, we use it as supplied. 3. We look in the first line of the program file for a shell redirector, e.g. '#!'. 4. If the program is defined as one handled by a standard shell, we will use that standard shell, with any arguments as needed. This is done internally in the redirect_via_interpreter() function. We then prepare the environment in envv (and set free_envv if envv was reallocated) and save/duplicate the stdio handles. The implementation must do a chroot and exec as necessary to run the command. This code may end with an error in procinfo-> error, which the envelope code must handle. */ /* Substitute in the defaults for values not supplied */ envv = procinfo-> envv? procinfo-> envv: environ; searchext = procinfo-> searchext? procinfo-> searchext: default_ext; path = procinfo-> path? procinfo-> path: "PATH"; shell = procinfo-> shell? procinfo-> shell: env_get_string (default_shell, ""); /* We start with the filename and the argv array */ /* If we are to run using a shell, then we don't split the filename */ /* string up (we leave that for the shell to do; important in unix) */ list_create (arglist, sizeof (ARGLIST)); if (procinfo-> useshell) arglist_add (arglist, LIST_AFTER, procinfo-> filename); else arglist_add_string (arglist, LIST_AFTER, procinfo-> filename); arglist_add_table (arglist, LIST_AFTER, procinfo-> argv); /* Now prefix the shell if necessary */ if (procinfo-> useshell) { arglist_add (arglist, LIST_BEFORE, shell_run); arglist_add (arglist, LIST_BEFORE, shell); interpreter = shell; } else if (file_is_program (arglist-> next-> value)) /* We're hunky-dory */ interpreter = NULL; else { /* Look for interpreter name as first line of file */ interpreter = redirect_via_interpreter (arglist-> next-> value, procinfo-> searchpath, path, searchext, shell); if (interpreter) { /* The interpreter string contains: * interpreter args...args script * which _replaces_ the first argument in our list, so we need * to remove that from out list. (This is important because * our existing first argument may have a relative path or * something like that, which will not work once we change * directories.) */ arglist_remove_first (arglist); arglist_add_string (arglist, LIST_BEFORE, interpreter); } else /* Redirection failed. This means that it isn't executable, * because we should either have got a full name back, or a * command string to run. */ procinfo-> error = ENOENT; /* No such file */ } /* Find the actual file we have to run. If we're allowed to search * the path, then we do that, otherwise we just look where we are. * This is a good moment to unescape any spaces in the filename... */ if (procinfo-> error == 0) { process_unesc (arglist-> next-> value, arglist-> next-> value); if (!interpreter && !procinfo-> searchpath) path = NULL; /* Don't search path */ full_filename = file_where_ext ('r', path, arglist-> next-> value, runnable_ext); if (full_filename == NULL) procinfo-> error = ENOENT; /* No such file */ else if (!file_is_executable (full_filename)) procinfo-> error = EACCES; /* No permission to access file */ } /* Create new environment as required. We * are merged into it, otherwise they are merged into environ */ if (procinfo-> error == 0 && (procinfo-> envadd != NULL || procinfo-> envrm != NULL)) { envv = merge_environment (envv, procinfo-> envadd, procinfo-> envrm); if (envv) free_envv = TRUE; else procinfo-> error = errno? errno: ENOMEM; } if (procinfo-> error == 0 && STDIN_FILENO >= 0) { /* Redirect the IO file handles for stdin, stdout, stderr, */ if (procinfo-> in != NULL_HANDLE) old_stdin = file_fhredirect (procinfo-> in, STDIN_FILENO); if (procinfo-> out != NULL_HANDLE) old_stdout = file_fhredirect (procinfo-> out, STDOUT_FILENO); if (procinfo-> err != NULL_HANDLE) old_stderr = file_fhredirect (procinfo-> err, STDERR_FILENO); if (old_stdin == -1 || old_stdout == -1 || old_stderr == -1) { procinfo-> error = errno? errno: EACCES; restore_redirection (old_stdin, old_stdout, old_stderr); } }