1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * @(#)mksh.cc 1.22 06/12/12
  27  */
  28 
  29 #pragma ident   "@(#)mksh.cc    1.22    06/12/12"
  30 
  31 /*
  32  *      mksh.cc
  33  *
  34  *      Execute the command(s) of one Make or DMake rule
  35  */
  36 
  37 /*
  38  * Included files
  39  */
  40 #if defined(TEAMWARE_MAKE_CMN) || defined(MAKETOOL) /* tolik */
  41 #       include <avo/util.h>
  42 #endif
  43 
  44 #include <mksh/dosys.h>           /* redirect_io() */
  45 #include <mksh/misc.h>            /* retmem() */
  46 #include <mksh/mksh.h>
  47 #include <mksdmsi18n/mksdmsi18n.h>
  48 #include <errno.h>
  49 #include <signal.h>
  50 
  51 #ifdef HP_UX
  52         extern void (*sigset(int, void (*)(__harg)))(__harg);
  53 #endif
  54 
  55 /*
  56  * Workaround for NFS bug. Sometimes, when running 'chdir' on a remote
  57  * dmake server, it fails with "Stale NFS file handle" error.
  58  * The second attempt seems to work.
  59  */
  60 int
  61 my_chdir(char * dir) {
  62         int res = chdir(dir);
  63         if (res != 0 && (errno == ESTALE || errno == EAGAIN)) {
  64                 /* Stale NFS file handle. Try again */
  65                 res = chdir(dir);
  66         }
  67         return res;
  68 }
  69 
  70 
  71 /*
  72  * File table of contents
  73  */
  74 static void     change_sunpro_dependencies_value(char *oldpath, char *newpath);
  75 static void     init_mksh_globals(char *shell);
  76 static void     set_env_vars(char *env_list[]);
  77 
  78 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
  79 /*
  80  *      Execute the command(s) of one Make or DMake rule
  81  */
  82 int
  83 do_job(Avo_DmakeCommand *cmd_list[], char *env_list[], char *stdout_file, char *stderr_file, char *cwd, char *cnwd, int ignore, int silent, pathpt vroot_path, char *shell, int nice_prio)
  84 {
  85         Boolean                 always_exec_flag;
  86         char                    *cmd;
  87         Avo_DmakeCommand        **cmd_list_p;
  88         Name                    command;
  89         Boolean                 do_not_exec_flag;
  90         Boolean                 ignore_flag;
  91         int                     length;
  92         Boolean                 make_refd_flag;
  93         Boolean                 meta_flag;
  94         char                    pathname[MAXPATHLEN];
  95         Doname                  result;
  96         Boolean                 silent_flag;
  97         wchar_t                 *tmp_wcs_buffer;
  98 
  99         if ((childPid = fork()) < 0) {       /* error */
 100                 ;
 101         } else if (childPid > 0) {           /* parent */
 102                 ;
 103         } else {                        /* child, mksh */
 104                 (void) sigset(SIGCHLD, SIG_DFL);
 105                 enable_interrupt(handle_interrupt_mksh);
 106                 /* set environment variables */
 107                 set_env_vars(env_list);
 108                 /* redirect stdout and stderr to temp files */
 109                 dup2(1, 2);     // Because fatal_mksh() prints error messages into
 110                                 // stderr but dmake uses stderr for XDR communications
 111                                 // and stdout for errors messages.
 112                 redirect_io(stdout_file, stderr_file);
 113                 /* try cd'ing to cwd */
 114                 if (my_chdir(cwd) != 0) {
 115                         /* try the netpath machine:pathname */
 116                         if (!avo_netpath_to_path(cnwd, pathname)) {
 117                                 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 137, "`cd %s' failed, and conversion of %s to automounter pathname also failed: %s"), cwd, cnwd, strerror(errno));
 118                         } else if (my_chdir(pathname) != 0) {
 119                                 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 138, "`cd %s' and `cd %s' both failed: %s"), cwd, pathname, strerror(errno));
 120                         }
 121                         /*
 122                          * change the value of SUNPRO_DEPENDENCIES
 123                          * to the new path.
 124                          */
 125                         change_sunpro_dependencies_value(cwd, pathname);
 126                 }
 127                 init_mksh_globals(shell);
 128                 for (cmd_list_p = cmd_list;
 129                      *cmd_list_p != (Avo_DmakeCommand *) NULL;
 130                      cmd_list_p++) {
 131                         if ((*cmd_list_p)->ignore()) {
 132                                 ignore_flag = true;
 133                         } else {
 134                                 ignore_flag = false;
 135                         }
 136                         if ((*cmd_list_p)->silent()) {
 137                                 silent_flag = true;
 138                         } else {
 139                                 silent_flag = false;
 140                         }
 141 /*
 142                         if ((*cmd_list_p)->always_exec()) {
 143                                 always_exec_flag = true;
 144                         } else {
 145                                 always_exec_flag = false;
 146                         }
 147  */
 148                         always_exec_flag = false;
 149                         if ((*cmd_list_p)->meta()) {
 150                                 meta_flag = true;
 151                         } else {
 152                                 meta_flag = false;
 153                         }
 154                         if ((*cmd_list_p)->make_refd()) {
 155                                 make_refd_flag = true;
 156                         } else {
 157                                 make_refd_flag = false;
 158                         }
 159                         if ((*cmd_list_p)->do_not_exec()) {
 160                                 do_not_exec_flag = true;
 161                         } else {
 162                                 do_not_exec_flag = false;
 163                         }
 164                         do_not_exec_rule = do_not_exec_flag;
 165                         cmd = (*cmd_list_p)->getCmd();
 166                         if ((length = strlen(cmd)) >= MAXPATHLEN) {
 167                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
 168                                 (void) mbstowcs(tmp_wcs_buffer, cmd, length + 1);
 169                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
 170                                 retmem(tmp_wcs_buffer);
 171                         } else {
 172                                 MBSTOWCS(wcs_buffer, cmd);
 173                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
 174                         }
 175                         if ((command->hash.length > 0) &&
 176                             (!silent_flag || do_not_exec_flag)) {
 177                                 (void) printf("%s\n", command->string_mb);
 178                         }
 179                         result = dosys_mksh(command,
 180                                             ignore_flag,
 181                                             make_refd_flag,
 182                                             false, /* bugs #4085164 & #4990057 */
 183                                             /* BOOLEAN(silent_flag && ignore_flag), */
 184                                             always_exec_flag,
 185                                             (Name) NULL,
 186                                             false,
 187                                             NULL,
 188                                             NULL,
 189                                             vroot_path,
 190                                             nice_prio);
 191                         if (result == build_failed) {
 192 
 193 #ifdef PRINT_EXIT_STATUS
 194                                 warning_mksh(NOCATGETS("I'm in do_job(), and dosys_mksh() returned result of build_failed."));
 195 #endif
 196 
 197                                 if (silent_flag) {
 198                                         (void) printf(catgets(libmksdmsi18n_catd, 1, 139, "The following command caused the error:\n%s\n"),
 199                                                       command->string_mb);
 200                                 }
 201                                 if (!ignore_flag && !ignore) {
 202 
 203 #ifdef PRINT_EXIT_STATUS
 204                                         warning_mksh(NOCATGETS("I'm in do_job(), and dosys_mksh() returned result of build_failed, exiting 1."));
 205 #endif
 206 
 207                                         exit(1);
 208                                 }
 209                         }
 210                 }
 211 
 212 #ifdef PRINT_EXIT_STATUS
 213                 warning_mksh(NOCATGETS("I'm in do_job(), exiting 0."));
 214 #endif
 215 
 216                 exit(0);
 217         }
 218         return childPid;
 219 }
 220 #endif /* TEAMWARE_MAKE_CMN */
 221 
 222 static void
 223 set_env_vars(char *env_list[])
 224 {
 225         char                    **env_list_p;
 226 
 227         for (env_list_p = env_list;
 228              *env_list_p != (char *) NULL;
 229              env_list_p++) {
 230                 putenv(*env_list_p);
 231         }
 232 }
 233 
 234 static void
 235 init_mksh_globals(char *shell)
 236 {
 237 /*
 238         MBSTOWCS(wcs_buffer, NOCATGETS("SHELL"));
 239         shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 240         MBSTOWCS(wcs_buffer, shell);
 241         (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
 242  */
 243         char * dmake_shell;
 244         if ((dmake_shell = getenv(NOCATGETS("DMAKE_SHELL"))) == NULL) {
 245                 dmake_shell = shell;
 246         } 
 247         MBSTOWCS(wcs_buffer, dmake_shell);
 248         shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 249 }
 250 
 251 /*
 252  * Change the pathname in the value of the SUNPRO_DEPENDENCIES env variable
 253  * from oldpath to newpath.
 254  */
 255 static void
 256 change_sunpro_dependencies_value(char *oldpath, char *newpath)
 257 {
 258         char            buf[MAXPATHLEN];
 259         static char     *env;
 260         int             length;
 261         int             oldpathlen;
 262         char            *sp_dep_value;
 263 
 264         /* check if SUNPRO_DEPENDENCIES is set in the environment */
 265         if ((sp_dep_value = getenv(NOCATGETS("SUNPRO_DEPENDENCIES"))) != NULL) {
 266                 oldpathlen = strlen(oldpath);
 267                 /* check if oldpath is indeed in the value of SUNPRO_DEPENDENCIES */
 268                 if (strncmp(oldpath, sp_dep_value, oldpathlen) == 0) {
 269                         (void) sprintf(buf,
 270                                        "%s%s",
 271                                        newpath,
 272                                        sp_dep_value + oldpathlen);
 273                         length = 2 +
 274                                 strlen(NOCATGETS("SUNPRO_DEPENDENCIES")) +
 275                                 strlen(buf);
 276                         env = getmem(length);
 277                         (void) sprintf(env,
 278                                        "%s=%s",
 279                                        NOCATGETS("SUNPRO_DEPENDENCIES"),
 280                                        buf);
 281                         (void) putenv(env);
 282                 }
 283         }
 284 }
 285 
 286