| 1 | #!/usr/bin/perl | 
|---|
| 2 | # IBM_PROLOG_BEGIN_TAG  | 
|---|
| 3 | # This is an automatically generated prolog.  | 
|---|
| 4 | #   | 
|---|
| 5 | #   | 
|---|
| 6 | #   | 
|---|
| 7 | # Licensed Materials - Property of IBM  | 
|---|
| 8 | #   | 
|---|
| 9 | # (C) COPYRIGHT International Business Machines Corp. 2000,2006  | 
|---|
| 10 | # All Rights Reserved  | 
|---|
| 11 | #   | 
|---|
| 12 | # US Government Users Restricted Rights - Use, duplication or  | 
|---|
| 13 | # disclosure restricted by GSA ADP Schedule Contract with IBM Corp.  | 
|---|
| 14 | #   | 
|---|
| 15 | # IBM_PROLOG_END_TAG  | 
|---|
| 16 | # @(#)24  1.50  src/avs/fs/mmfs/ts/admin/mmdsh, mmfs, avs_rgpfs24, rgpfs240610b 2/12/06 12:34:29 | 
|---|
| 17 | ############################################################################# | 
|---|
| 18 | # | 
|---|
| 19 | # Module:  mmdsh | 
|---|
| 20 | # | 
|---|
| 21 | #CPRY | 
|---|
| 22 | # 5765-296 (C) Copyright IBM Corporation 1994, 2000 | 
|---|
| 23 | # Licensed Materials - Property of IBM | 
|---|
| 24 | # All rights reserved. | 
|---|
| 25 | # US Government Users Restricted Rights - | 
|---|
| 26 | # Use, duplication or disclosure restricted by | 
|---|
| 27 | # GSA ADP Schedule Contract with IBM Corp. | 
|---|
| 28 | #CPRY | 
|---|
| 29 | # | 
|---|
| 30 | ############################################################################# | 
|---|
| 31 | # | 
|---|
| 32 | # Description:  command for running commands on multiple nodes or | 
|---|
| 33 | #               network connected hosts in parallel | 
|---|
| 34 | # | 
|---|
| 35 | #   mmdsh [-isv] [-f num] [-F hostlistfile] [-L listofhosts] [-I file] [-k] | 
|---|
| 36 | #         [-N nodespecification] [-R reportfile] [-r] [command] | 
|---|
| 37 | # | 
|---|
| 38 | # Flags/parms: | 
|---|
| 39 | # | 
|---|
| 40 | # [-f num]    Specifies a fanout value used for concurrent execution. | 
|---|
| 41 | # | 
|---|
| 42 | # [-F hostlistfile] | 
|---|
| 43 | #             Runs the command on the hosts in the specified hostlistfile. | 
|---|
| 44 | #             The hostlistfile argument is the fully qualified name | 
|---|
| 45 | #             of a file that lists the names of the desired hosts, | 
|---|
| 46 | #             one host per line. | 
|---|
| 47 | # | 
|---|
| 48 | # [-i]        Displays the set of nodes on which the command will run | 
|---|
| 49 | #             before command execution. | 
|---|
| 50 | # | 
|---|
| 51 | # [-I file]   Name of the file to be copied on the remote node prior | 
|---|
| 52 | #             to executing the command.  The file must be in /var/mmfs/tmp. | 
|---|
| 53 | #             This option can be specified twice. | 
|---|
| 54 | # | 
|---|
| 55 | # [-k]        Remove files specified with the -I flag before exiting. | 
|---|
| 56 | # | 
|---|
| 57 | # [-L listofhosts] | 
|---|
| 58 | #             Runs the command on the specified list of hosts. | 
|---|
| 59 | #             The listofhosts argument is a comma-separated list of hosts. | 
|---|
| 60 | # | 
|---|
| 61 | # [-N nodespecification] | 
|---|
| 62 | #             Runs the command on the nodes in the given node specification. | 
|---|
| 63 | #             The nodespecification argument can be a comma-separated list of | 
|---|
| 64 | #             nodes, a node file, or a node class.  The nodes in the list or | 
|---|
| 65 | #             the file can be specified as long or short admin or daemon | 
|---|
| 66 | #             node names, node numbers, node number ranges, or IP addresses. | 
|---|
| 67 | # | 
|---|
| 68 | # [-R reportfile] | 
|---|
| 69 | #             Reports the list of hosts removed from the working collective | 
|---|
| 70 | #             when host verification (host ping) fails.  The report is written | 
|---|
| 71 | #             to the specified file with one host per line.  The report is | 
|---|
| 72 | #             generated only when combined with the '-v' flag. | 
|---|
| 73 | # | 
|---|
| 74 | # [-r]        Reports the list of hosts removed from the working collective | 
|---|
| 75 | #             when host verification (host ping) fails.  The report is written | 
|---|
| 76 | #             to standard error.  The report is generated only when combined | 
|---|
| 77 | #             with the '-v' flag. | 
|---|
| 78 | # | 
|---|
| 79 | # [-s]        Suppresses the prepending of the hostname string to each line | 
|---|
| 80 | #             of output generated by running the command on the remote host. | 
|---|
| 81 | # | 
|---|
| 82 | # [-v]        Verify that each host is reachable before adding it to the | 
|---|
| 83 | #             set of nodes on which the command will run. | 
|---|
| 84 | # | 
|---|
| 85 | # [command]   command to be run on the remote hosts. | 
|---|
| 86 | #             If the command is the reserved word "_SELECT_FROM_FILE_", | 
|---|
| 87 | #             then the commands to be run on the different hosts are | 
|---|
| 88 | #             expected to be in the file pointed to by the environment | 
|---|
| 89 | #             variable mmdshCommandsFile.  Each line of this file consists | 
|---|
| 90 | #             of hostname followed by a command string. | 
|---|
| 91 | # | 
|---|
| 92 | # Outputs: | 
|---|
| 93 | #   The command is executed on the specified host(s). | 
|---|
| 94 | # | 
|---|
| 95 | # Examples: | 
|---|
| 96 | #   mmdsh -F /nodes uname -a | 
|---|
| 97 | #   mmdsh -L host1,host2,host3 ls | 
|---|
| 98 | #   mmdsh -N quorumnodes date | 
|---|
| 99 | # | 
|---|
| 100 | ############################################################################# | 
|---|
| 101 |  | 
|---|
| 102 | # Obtain valid "waitpid" flags. | 
|---|
| 103 | use POSIX ":sys_wait_h"; | 
|---|
| 104 |  | 
|---|
| 105 | $MMCOMMON="/usr/lpp/mmfs/bin/mmcommon"; | 
|---|
| 106 | $REL_HOSTNAME_Field=8; | 
|---|
| 107 |  | 
|---|
| 108 |  | 
|---|
| 109 | #---------------------------------------------------------------------------- | 
|---|
| 110 | # | 
|---|
| 111 | # Function:  Correct the return value from system() and etc. | 
|---|
| 112 | # | 
|---|
| 113 | #---------------------------------------------------------------------------- | 
|---|
| 114 | sub normalizeRC | 
|---|
| 115 | { | 
|---|
| 116 |   local ($rc); | 
|---|
| 117 |  | 
|---|
| 118 |   $rc = $_[0] + 0; | 
|---|
| 119 |   if ($rc >= 256) { $rc = $rc / 256; } | 
|---|
| 120 |  | 
|---|
| 121 |   return $rc; | 
|---|
| 122 |  | 
|---|
| 123 | }  #---- end of function normalizeRC ----------------------------------- | 
|---|
| 124 |  | 
|---|
| 125 |  | 
|---|
| 126 | #---------------------------------------------------------------------------- | 
|---|
| 127 | # | 
|---|
| 128 | # Function:  Print a message using the message catalog facilities. | 
|---|
| 129 | # | 
|---|
| 130 | # Input:     $_[0] - message number in catalog | 
|---|
| 131 | #            $_[1] - message text formatting string | 
|---|
| 132 | #            ...   - optional message parameters (up to 5) | 
|---|
| 133 | # | 
|---|
| 134 | #---------------------------------------------------------------------------- | 
|---|
| 135 |  | 
|---|
| 136 | sub prtMsg | 
|---|
| 137 | { | 
|---|
| 138 |   local ($msgNum) = shift(@_); | 
|---|
| 139 |   local ($p1)     = shift(@_); | 
|---|
| 140 |   local ($p2)     = shift(@_); | 
|---|
| 141 |   local ($p3)     = shift(@_); | 
|---|
| 142 |   local ($p4)     = shift(@_); | 
|---|
| 143 |   local ($p5)     = shift(@_); | 
|---|
| 144 |  | 
|---|
| 145 |   local ($msgTxt); | 
|---|
| 146 |   local ($prog); | 
|---|
| 147 |  | 
|---|
| 148 |   chop($prog = `/bin/basename $0`); | 
|---|
| 149 |    | 
|---|
| 150 |   for ($msgNum) { | 
|---|
| 151 |  | 
|---|
| 152 |     if    (/^13$/) | 
|---|
| 153 |     { | 
|---|
| 154 |       $msgTxt="%s:  Incorrect option: %s"; | 
|---|
| 155 |     } | 
|---|
| 156 |     elsif (/^36$/) | 
|---|
| 157 |     { | 
|---|
| 158 |       $msgTxt="%s:  %s flag specified twice."; | 
|---|
| 159 |     } | 
|---|
| 160 |     elsif (/^38$/) | 
|---|
| 161 |     { | 
|---|
| 162 |       $msgTxt="%s:  Invalid extra argument: %s"; | 
|---|
| 163 |     } | 
|---|
| 164 |     elsif (/^40$/) | 
|---|
| 165 |     { | 
|---|
| 166 |       $msgTxt="%s:  Invalid integer for %s: %s"; | 
|---|
| 167 |     } | 
|---|
| 168 |     elsif (/^153$/) | 
|---|
| 169 |     { | 
|---|
| 170 |       $msgTxt="%s:  Invalid value for %s flag"; | 
|---|
| 171 |     } | 
|---|
| 172 |     elsif (/^168$/) | 
|---|
| 173 |     { | 
|---|
| 174 |       $msgTxt="%s:  The device name %s starts with a slash, but not /dev/."; | 
|---|
| 175 |     } | 
|---|
| 176 |     elsif (/^171$/) | 
|---|
| 177 |     { | 
|---|
| 178 |       $msgTxt="%s:  Unexpected error from %s. Return code: %s"; | 
|---|
| 179 |     } | 
|---|
| 180 |     elsif (/^204$/) | 
|---|
| 181 |     { | 
|---|
| 182 |       $msgTxt="%s:  Missing argument after %s flag"; | 
|---|
| 183 |     } | 
|---|
| 184 |     elsif (/^206$/) | 
|---|
| 185 |     { | 
|---|
| 186 |       $msgTxt="Command %s failed with return code %s."; | 
|---|
| 187 |     } | 
|---|
| 188 |     elsif (/^362$/) | 
|---|
| 189 |     { | 
|---|
| 190 |       $msgTxt="%s:  Nodes on which the command will be run:"; | 
|---|
| 191 |     } | 
|---|
| 192 |     elsif (/^363$/) | 
|---|
| 193 |     { | 
|---|
| 194 |       $msgTxt="%s:  WCOLL (working collective) environment variable not set."; | 
|---|
| 195 |     } | 
|---|
| 196 |     elsif (/^364$/) | 
|---|
| 197 |     { | 
|---|
| 198 |       $msgTxt="%s:  Cannot open file %s.  Error string was:  %s"; | 
|---|
| 199 |     } | 
|---|
| 200 |     elsif (/^365$/) | 
|---|
| 201 |     { | 
|---|
| 202 |       $msgTxt="%s:  %s remote shell process had return code %s."; | 
|---|
| 203 |     } | 
|---|
| 204 |     elsif (/^366$/) | 
|---|
| 205 |     { | 
|---|
| 206 |       $msgTxt="%s:  Caught SIG %s - terminating the child processes."; | 
|---|
| 207 |     } | 
|---|
| 208 |     elsif (/^367$/) | 
|---|
| 209 |     { | 
|---|
| 210 |       $msgTxt="%s:  There are no available nodes on which to run the command."; | 
|---|
| 211 |     } | 
|---|
| 212 |     elsif (/^368$/) | 
|---|
| 213 |     { | 
|---|
| 214 |       $msgTxt="%s:  Unable to pipe.  Error string was:  %s"; | 
|---|
| 215 |     } | 
|---|
| 216 |     elsif (/^369$/) | 
|---|
| 217 |     { | 
|---|
| 218 |       $msgTxt="%s:  Unable to redirect %s.  Error string was:  %s"; | 
|---|
| 219 |     } | 
|---|
| 220 |     elsif (/^422$/) | 
|---|
| 221 |     { | 
|---|
| 222 |       $msgTxt="%s:  Invalid or missing remote shell command:  %s"; | 
|---|
| 223 |     } | 
|---|
| 224 |     elsif (/^423$/) | 
|---|
| 225 |     { | 
|---|
| 226 |       $msgTxt="%s:  Invalid or missing remote file copy command:  %s"; | 
|---|
| 227 |     } | 
|---|
| 228 |     elsif (/^573$/) | 
|---|
| 229 |     { | 
|---|
| 230 |       $msgTxt="%s:  Node %s is not available to run the command."; | 
|---|
| 231 |     } | 
|---|
| 232 |     else            # should never happen | 
|---|
| 233 |     { | 
|---|
| 234 |       $msgTxt="\n%s:  An unknown error number %s was passed to prtMsg."; | 
|---|
| 235 |       printf STDERR  "$msgTxt\n\n", $prog, $msgNum; | 
|---|
| 236 |       return; | 
|---|
| 237 |     } | 
|---|
| 238 |   } | 
|---|
| 239 |  | 
|---|
| 240 |   if ($osName eq "AIX") | 
|---|
| 241 |   { | 
|---|
| 242 |     $msg=`$DSPMSG $msgNum \"$msgTxt\" \"$prog\" \"$p1\" \"$p2\" \"$p3\" \"$p4\" \"$p5\"`; | 
|---|
| 243 |     printf STDERR  "$msg\n"; | 
|---|
| 244 |   } | 
|---|
| 245 |   else | 
|---|
| 246 |   { | 
|---|
| 247 |     printf STDERR  "$msgTxt\n", $prog, $p1, $p2, $p3, $p4, $p5; | 
|---|
| 248 |   } | 
|---|
| 249 |  | 
|---|
| 250 | }  #---- end of function prtMsg ---------------------------------------- | 
|---|
| 251 |  | 
|---|
| 252 |  | 
|---|
| 253 | #---------------------------------------------------------------------------- | 
|---|
| 254 | # | 
|---|
| 255 | # read_pipes_and_wait | 
|---|
| 256 | # | 
|---|
| 257 | # Read STDOUT and STDERR on specified child rsh process pipes. | 
|---|
| 258 | # Display to parent's STDOUT or STDERR.  If the '-s' flag is not | 
|---|
| 259 | # specified, then host output is preceded by "hostname:  ". | 
|---|
| 260 | # | 
|---|
| 261 | # Output from STDERR is first written to an array, since there is | 
|---|
| 262 | # a limit of 32k from STDERR before it ends up hanging. | 
|---|
| 263 | # | 
|---|
| 264 | # Reap completed children to allow additional child processes to be | 
|---|
| 265 | # spawned for fanout maintenance. | 
|---|
| 266 | # | 
|---|
| 267 | # Parameters: | 
|---|
| 268 | #   final_read -- true to "read/wait" on all specified children, false | 
|---|
| 269 | #                 to only "read" currently available data for specified | 
|---|
| 270 | #                 children and reap any completed children for fanout | 
|---|
| 271 | #                 maintenance. | 
|---|
| 272 | #   hosts      -- Array of hostnames with STDOUT/STDERR pipes to query. | 
|---|
| 273 | # | 
|---|
| 274 | #---------------------------------------------------------------------------- | 
|---|
| 275 |  | 
|---|
| 276 | sub read_pipes_and_wait { | 
|---|
| 277 |  | 
|---|
| 278 |   my $final_read = shift; | 
|---|
| 279 |  | 
|---|
| 280 |   local(@hosts) = @_; | 
|---|
| 281 |  | 
|---|
| 282 |   local($fno,$fh,$rin,$rout,$num_fh,$host,$err_ctr,$array_updated,$offset); | 
|---|
| 283 |  | 
|---|
| 284 |   # Initialize the pipes read select vector. | 
|---|
| 285 |   $rin = ''; | 
|---|
| 286 |   $num_fh = 0; | 
|---|
| 287 |   foreach $host (@hosts) { | 
|---|
| 288 |     if (($fno = fileno($r_out{$host})) ne '') { | 
|---|
| 289 |       vec($rin, $fno, 1) = 1; | 
|---|
| 290 |       $num_fh++; | 
|---|
| 291 |     } | 
|---|
| 292 |     if (($fno = fileno($r_err{$host})) ne '') { | 
|---|
| 293 |       vec($rin, $fno, 1) = 1; | 
|---|
| 294 |       $num_fh++; | 
|---|
| 295 |     } | 
|---|
| 296 |   } | 
|---|
| 297 |  | 
|---|
| 298 |   $err_ctr = 0; | 
|---|
| 299 |   $array_updated = 0; | 
|---|
| 300 |  | 
|---|
| 301 |   READWAIT: { | 
|---|
| 302 |  | 
|---|
| 303 |     if ($num_fh > 0) { | 
|---|
| 304 |       # Wait for outstanding I/O on read pipes. | 
|---|
| 305 |       $nready = select($rout = $rin, undef, undef, undef); | 
|---|
| 306 |       if ($nready > 0) { | 
|---|
| 307 |         # At least one pipe has available data. | 
|---|
| 308 |         foreach $host (@hosts) { | 
|---|
| 309 |  | 
|---|
| 310 |           # Process STDOUT I/O | 
|---|
| 311 |           $fh = $r_out{$host}; | 
|---|
| 312 |           if (vec($rout, fileno($fh), 1)) { | 
|---|
| 313 |             $_ = <$fh>; | 
|---|
| 314 |             if (length($_)) { | 
|---|
| 315 |               if ($sflag) { | 
|---|
| 316 |                print STDOUT "$_"; | 
|---|
| 317 |               } | 
|---|
| 318 |               else { | 
|---|
| 319 |                print STDOUT "$host:  $_"; | 
|---|
| 320 |               } | 
|---|
| 321 |             } | 
|---|
| 322 |             else { | 
|---|
| 323 |               # EOF has been reached | 
|---|
| 324 |               vec($rin, fileno($fh), 1) = 0; | 
|---|
| 325 |               $num_fh--; | 
|---|
| 326 |               close($fh); | 
|---|
| 327 |             } | 
|---|
| 328 |           } | 
|---|
| 329 |  | 
|---|
| 330 |           # Process STDERR I/O. | 
|---|
| 331 |           $fh = $r_err{$host}; | 
|---|
| 332 |           if (vec($rout, fileno($fh), 1)) { | 
|---|
| 333 |             $_ = <$fh>; | 
|---|
| 334 |             if (length($_)) { | 
|---|
| 335 |               if ($sflag) { | 
|---|
| 336 |                 $stderr_array[$err_ctr] = $_; | 
|---|
| 337 |               } | 
|---|
| 338 |               else { | 
|---|
| 339 |                 $stderr_array[$err_ctr] = "$host:  $_"; | 
|---|
| 340 |               } | 
|---|
| 341 |               $err_ctr++; | 
|---|
| 342 |               $array_updated = 1; | 
|---|
| 343 |             } | 
|---|
| 344 |             else { | 
|---|
| 345 |               # EOF has been reached | 
|---|
| 346 |               vec($rin, fileno($fh), 1) = 0; | 
|---|
| 347 |               $num_fh--; | 
|---|
| 348 |               close($fh); | 
|---|
| 349 |             } | 
|---|
| 350 |           } | 
|---|
| 351 |         } | 
|---|
| 352 |       } | 
|---|
| 353 |  | 
|---|
| 354 |       # Reap any completed child process, in order to maintain fanout. | 
|---|
| 355 |       if (($child_pid = waitpid(-1, &WNOHANG)) > 0) { | 
|---|
| 356 |  | 
|---|
| 357 |         # Obtain the return code and hostname for the child process. | 
|---|
| 358 |         $child_rc = $? >> 8; | 
|---|
| 359 |         foreach (keys %pid) { | 
|---|
| 360 |           if ($pid{$_} == $child_pid) { | 
|---|
| 361 |             $child_host = $_; | 
|---|
| 362 |             last; | 
|---|
| 363 |           } | 
|---|
| 364 |         } | 
|---|
| 365 |  | 
|---|
| 366 |         # Process any outstanding STDOUT I/O for the deceased child. | 
|---|
| 367 |         $fh = $r_out{$child_host}; | 
|---|
| 368 |         if (fileno($fh) != undef) { | 
|---|
| 369 |           do { | 
|---|
| 370 |             $_ = <$fh>; | 
|---|
| 371 |             if (length($_)) | 
|---|
| 372 |             { | 
|---|
| 373 |               if ($sflag) { | 
|---|
| 374 |                 print STDOUT "$_"; | 
|---|
| 375 |               } | 
|---|
| 376 |               else { | 
|---|
| 377 |                 print STDOUT "$child_host:  $_"; | 
|---|
| 378 |               } | 
|---|
| 379 |             } | 
|---|
| 380 |           } while (length($_)); | 
|---|
| 381 |  | 
|---|
| 382 |           # EOF has been reached | 
|---|
| 383 |           vec($rin, fileno($fh), 1) = 0; | 
|---|
| 384 |           $num_fh--; | 
|---|
| 385 |           close($fh); | 
|---|
| 386 |         } | 
|---|
| 387 |  | 
|---|
| 388 |         # Process any outstanding STDERR I/O for the deceased child. | 
|---|
| 389 |         $fh = $r_err{$child_host}; | 
|---|
| 390 |         if (fileno($fh) != undef) { | 
|---|
| 391 |           do { | 
|---|
| 392 |             $_ = <$fh>; | 
|---|
| 393 |             if (length($_)) { | 
|---|
| 394 |               if ($sflag) { | 
|---|
| 395 |                 $stderr_array[$err_ctr] = $_; | 
|---|
| 396 |               } | 
|---|
| 397 |               else { | 
|---|
| 398 |                 $stderr_array[$err_ctr] = "$child_host:  $_"; | 
|---|
| 399 |               } | 
|---|
| 400 |               $err_ctr++; | 
|---|
| 401 |               $array_updated = 1; | 
|---|
| 402 |             } | 
|---|
| 403 |           } while (length($_)); | 
|---|
| 404 |  | 
|---|
| 405 |           # EOF has been reached | 
|---|
| 406 |           vec($rin, fileno($fh), 1) = 0; | 
|---|
| 407 |           $num_fh--; | 
|---|
| 408 |           close($fh); | 
|---|
| 409 |         } | 
|---|
| 410 |  | 
|---|
| 411 |         if ($child_rc != 0) { | 
|---|
| 412 |           if ($hostCount == 1) { | 
|---|
| 413 |             $rcode = $child_rc;   # Pass back child's rc to mmdsh caller | 
|---|
| 414 |           } | 
|---|
| 415 |           else { | 
|---|
| 416 |             $rcode++; | 
|---|
| 417 |             #print STDERR "mmdsh: $child_host rsh had exit code $child_rc\n"; | 
|---|
| 418 |             &prtMsg(365, $child_host, $child_rc); | 
|---|
| 419 |           } | 
|---|
| 420 |           push(@goners,$child_host); | 
|---|
| 421 |         } | 
|---|
| 422 |  | 
|---|
| 423 |         # Remove the deceased child from @hs so we don't continually try to add | 
|---|
| 424 |         # it to the select vector as problems may occur with sufficiently large | 
|---|
| 425 |         # numbers of nodes. | 
|---|
| 426 |         $offset = 0; | 
|---|
| 427 |         foreach $host (@hs) { | 
|---|
| 428 |           if ($host eq $child_host) { | 
|---|
| 429 |             splice(@hs, $offset, 1); | 
|---|
| 430 |             last; | 
|---|
| 431 |           } | 
|---|
| 432 |           $offset++; | 
|---|
| 433 |         } | 
|---|
| 434 |  | 
|---|
| 435 |         # Child terminated ==> decrement fanout | 
|---|
| 436 |         $cur_fanout--; | 
|---|
| 437 |       } | 
|---|
| 438 |  | 
|---|
| 439 |       if (($final_read eq true) && ($num_fh > 0) || | 
|---|
| 440 |           ($cur_fanout >= $fanout)) { | 
|---|
| 441 |         # Final pipes data retrieval ==> Wait/retrieve until all pipes closed | 
|---|
| 442 |         redo READWAIT; | 
|---|
| 443 |       } | 
|---|
| 444 |     } | 
|---|
| 445 |   } | 
|---|
| 446 |  | 
|---|
| 447 |   # Print out accumulated STDERR output. | 
|---|
| 448 |   if ($array_updated) { | 
|---|
| 449 |     for ($prt_ctr=0; $prt_ctr < $err_ctr; $prt_ctr++) { | 
|---|
| 450 |       print STDERR "$stderr_array[$prt_ctr]"; | 
|---|
| 451 |     } | 
|---|
| 452 |   } | 
|---|
| 453 |  | 
|---|
| 454 | }  #---------- end of read_pipes_and_wait routine --------------------------- | 
|---|
| 455 |  | 
|---|
| 456 |  | 
|---|
| 457 | #---------------------------------------------------------------------------- | 
|---|
| 458 | # | 
|---|
| 459 | # get_command | 
|---|
| 460 | # | 
|---|
| 461 | # Return the command from the command line or stdin. | 
|---|
| 462 | # Return 0 if no more to be read from command line or stdin. | 
|---|
| 463 | # If the command is in double quotes, add a double quote to the beginning. | 
|---|
| 464 | # If the command starts with '!', execute here and read in the next command. | 
|---|
| 465 | # | 
|---|
| 466 | #---------------------------------------------------------------------------- | 
|---|
| 467 |  | 
|---|
| 468 | sub get_command { | 
|---|
| 469 |  | 
|---|
| 470 |   local($command); | 
|---|
| 471 |   if ($done) { | 
|---|
| 472 |     return(0); | 
|---|
| 473 |   } | 
|---|
| 474 |   if (@ARGV) { | 
|---|
| 475 |     $done = 1; | 
|---|
| 476 |     @dsh_ARGV = @ARGV; | 
|---|
| 477 |     shift(@ARGV); | 
|---|
| 478 |     # | 
|---|
| 479 |     # Save the arguments in a scalar.  The return value | 
|---|
| 480 |     # of this routine is assigned to a scalar variable. | 
|---|
| 481 |     # | 
|---|
| 482 |     $dsh_return = join(' ',@dsh_ARGV); | 
|---|
| 483 |     return($dsh_return); | 
|---|
| 484 |   } | 
|---|
| 485 |   GET_COMMAND: { | 
|---|
| 486 |     -t && print STDERR "mmdsh> "; | 
|---|
| 487 |     $command = <STDIN>; | 
|---|
| 488 |     if (!defined($command)  || | 
|---|
| 489 |       $command =~ /^\s*$/ || $command =~ /^\s*exit\s*$/) { | 
|---|
| 490 |       return(0); | 
|---|
| 491 |     } else { | 
|---|
| 492 |       chop $command; | 
|---|
| 493 |       # Add a double-quote to the beginning of the command if the user | 
|---|
| 494 |       # entered the command with double-quotes. | 
|---|
| 495 |       if ($command =~ /^\s*"(.*)/) { | 
|---|
| 496 |         $command = '"' . $command; | 
|---|
| 497 |       } | 
|---|
| 498 |       if ($command =~ /^\s*!(.*)/) { | 
|---|
| 499 |         &do_system($1); | 
|---|
| 500 |         redo GET_COMMAND; | 
|---|
| 501 |       } else { | 
|---|
| 502 |         return($command) || redo GET_COMMAND; | 
|---|
| 503 |       } | 
|---|
| 504 |     } | 
|---|
| 505 |   } | 
|---|
| 506 |  | 
|---|
| 507 | }  #---------- end of get_command routine ------------------------------ | 
|---|
| 508 |  | 
|---|
| 509 |  | 
|---|
| 510 | #---------------------------------------------------------------------------- | 
|---|
| 511 | # | 
|---|
| 512 | # do_system | 
|---|
| 513 | # | 
|---|
| 514 | # Issue system() call with default signal handling. | 
|---|
| 515 | # Return the executed command's exit code. | 
|---|
| 516 | # | 
|---|
| 517 | #---------------------------------------------------------------------------- | 
|---|
| 518 |  | 
|---|
| 519 | sub do_system { | 
|---|
| 520 |  | 
|---|
| 521 |   local($command) = @_; | 
|---|
| 522 |   local(%save_sig,$rc); | 
|---|
| 523 |   %save_sig = %SIG; | 
|---|
| 524 |   grep($_ = 'DEFAULT', %SIG); | 
|---|
| 525 |   $rc = system("$command 2>&1") >> 8; | 
|---|
| 526 |   %SIG = %save_sig; | 
|---|
| 527 |   return($rc); | 
|---|
| 528 |  | 
|---|
| 529 | }  #---------- end of do_system routine --------------------------------- | 
|---|
| 530 |  | 
|---|
| 531 |  | 
|---|
| 532 | #---------------------------------------------------------------------------- | 
|---|
| 533 | # | 
|---|
| 534 | # display_help | 
|---|
| 535 | # | 
|---|
| 536 | # Display help information | 
|---|
| 537 | # | 
|---|
| 538 | #---------------------------------------------------------------------------- | 
|---|
| 539 |  | 
|---|
| 540 | sub display_help { | 
|---|
| 541 |  | 
|---|
| 542 |   $usageMsg=" | 
|---|
| 543 | Usage: | 
|---|
| 544 |  | 
|---|
| 545 |   mmdsh [flags/parms] command | 
|---|
| 546 |  | 
|---|
| 547 | Flags/parms: | 
|---|
| 548 |  | 
|---|
| 549 |   -f number     fanout number to use for concurrent execution | 
|---|
| 550 |   -F filename   nodelist file listing nodes on which to execute command | 
|---|
| 551 |   -I filename   file to be staged on the remote node prior to executing | 
|---|
| 552 |                   command; the file must be in /var/mmfs/tmp | 
|---|
| 553 |   -k            remove the file specified with the -I flag before exiting | 
|---|
| 554 |   -L n1,n2,n3   comma-separated list of nodes on which to execute command | 
|---|
| 555 |   -N nodespec   node specificaton that consists of a node list, a node file, | 
|---|
| 556 |                   or a node class on which to execute the command | 
|---|
| 557 |   -s            suppress the prepending of the hostname string to each line | 
|---|
| 558 |                   of output generated by running the command on the remote node | 
|---|
| 559 |   -v            verify that nodes are reachable before adding them to the | 
|---|
| 560 |                   set of nodes on which to run the command | 
|---|
| 561 |   -i            display the set of nodes on which the command will run | 
|---|
| 562 |                   before command execution | 
|---|
| 563 | "; | 
|---|
| 564 |   print STDERR "$usageMsg\n"; | 
|---|
| 565 |  | 
|---|
| 566 | }  #---------- end of display_help routine ----------------------------- | 
|---|
| 567 |  | 
|---|
| 568 |  | 
|---|
| 569 | #---------------------------------------------------------------------------- | 
|---|
| 570 | # | 
|---|
| 571 | # add_wc | 
|---|
| 572 | # | 
|---|
| 573 | # Add a host to the working collective. | 
|---|
| 574 | # | 
|---|
| 575 | # Input parameter is the hostname to be added. | 
|---|
| 576 | # | 
|---|
| 577 | # Don't add a hostname if it is already in the working collective. | 
|---|
| 578 | # | 
|---|
| 579 | #---------------------------------------------------------------------------- | 
|---|
| 580 |  | 
|---|
| 581 | sub add_wc { | 
|---|
| 582 |  | 
|---|
| 583 |    local($host) = @_; | 
|---|
| 584 |    local($hostname); | 
|---|
| 585 |  | 
|---|
| 586 |    $host =~ s/\s//g; | 
|---|
| 587 |  | 
|---|
| 588 |    # If the host is already in the working collective, return to the caller | 
|---|
| 589 |    #  without adding it to the collective again (avoid redundancies). | 
|---|
| 590 |    foreach $hostname (@wc) { | 
|---|
| 591 |       return if $hostname eq $host; | 
|---|
| 592 |    } | 
|---|
| 593 |  | 
|---|
| 594 |    # If we made it this far, add the host to the working collective. | 
|---|
| 595 |    push(@wc,$host); | 
|---|
| 596 |  | 
|---|
| 597 | }    #---------- end of add_wc routine ------------------------------------ | 
|---|
| 598 |  | 
|---|
| 599 |  | 
|---|
| 600 | #---------------------------------------------------------------------------- | 
|---|
| 601 | # | 
|---|
| 602 | # add_wc_parallel | 
|---|
| 603 | # | 
|---|
| 604 | # Add hosts to the working collective in parallel via fork. | 
|---|
| 605 | # | 
|---|
| 606 | # Input parameter is the opened working collective file handle. | 
|---|
| 607 | # | 
|---|
| 608 | # If -v was specified, only add a host to the working collective | 
|---|
| 609 | # if it is reachable via ping, or if the user said to add it | 
|---|
| 610 | # even though it is not reachable. | 
|---|
| 611 | # | 
|---|
| 612 | # Don't add a hostname if it is already in the working collective. | 
|---|
| 613 | # | 
|---|
| 614 | #---------------------------------------------------------------------------- | 
|---|
| 615 |  | 
|---|
| 616 | sub add_wc_parallel { | 
|---|
| 617 |  | 
|---|
| 618 |   local($filehandle) = @_; | 
|---|
| 619 |   local(@hosts_seen, $child_host); | 
|---|
| 620 |  | 
|---|
| 621 |   # Unlink the temporary file here.  Otherwise, it may be | 
|---|
| 622 |   # left behind if we run into a problem and exit early. | 
|---|
| 623 |   if ($hlfile) { | 
|---|
| 624 |     `/bin/rm -f $hlfile`; | 
|---|
| 625 |   } | 
|---|
| 626 |  | 
|---|
| 627 |   if ($fanout) {      # set fanval from user value, environment, or default | 
|---|
| 628 |     $fanval = $fanout; | 
|---|
| 629 |   } else { | 
|---|
| 630 |     unless ($fanval = $ENV{'FANOUT'}) { | 
|---|
| 631 |       $fanval = $fanout_default; | 
|---|
| 632 |     } | 
|---|
| 633 |   } | 
|---|
| 634 |  | 
|---|
| 635 |   HOST: while ($host = <$filehandle>) { | 
|---|
| 636 |  | 
|---|
| 637 |     $host =~ /^\s*#/ && next; | 
|---|
| 638 |     $host =~ /^\s*$/ && next; | 
|---|
| 639 |     $host =~ /;/ && next; | 
|---|
| 640 |     $host =~ /\S+\s+\S+/ && next; | 
|---|
| 641 |     chop($host); | 
|---|
| 642 |  | 
|---|
| 643 |     # Remove any leading or trailing whitespace. | 
|---|
| 644 |     ($host, $remainder) = split(" ", $host); | 
|---|
| 645 |  | 
|---|
| 646 |     # Prevent duplicates in the working collective.  Duplicates are culled | 
|---|
| 647 |     # here to prevent the key collisions in the %pid hashtable, which can | 
|---|
| 648 |     # cause unexpected behavior.  For example, defined, but empty hostnames | 
|---|
| 649 |     # being added to the working collective, leading to "Unknown host" | 
|---|
| 650 |     # messages from the remote shell during execution attempts. | 
|---|
| 651 |     foreach (@hosts_seen) { | 
|---|
| 652 |       if ($_ eq $host) { | 
|---|
| 653 |         next HOST; | 
|---|
| 654 |       } | 
|---|
| 655 |     } | 
|---|
| 656 |     push(@hosts_seen, $host); | 
|---|
| 657 |  | 
|---|
| 658 |     # Create filehandles for pipe ends. | 
|---|
| 659 |     $Rout{$host} = "READ_STDOUT__" . $host; | 
|---|
| 660 |     $Wout{$host} = "WRITE_STDOUT__" . $host; | 
|---|
| 661 |     $Rerr{$host} = "READ_STDERR__" . $host; | 
|---|
| 662 |     $Werr{$host} = "WRITE_STDERR__" . $host; | 
|---|
| 663 |  | 
|---|
| 664 |     # Open pipes for this host's stdout and stderr from ping. | 
|---|
| 665 |     if (pipe($Rout{$host}, $Wout{$host}) < 0) { | 
|---|
| 666 |       #die "mmdsh: Couldn't pipe: $!\n"; | 
|---|
| 667 |       &prtMsg(368, "\'$!\'"); | 
|---|
| 668 |       exit(-1); | 
|---|
| 669 |     } | 
|---|
| 670 |     if (pipe($Rerr{$host}, $Werr{$host}) < 0) { | 
|---|
| 671 |       #die "mmdsh: Couldn't pipe: $!\n"; | 
|---|
| 672 |       &prtMsg(368, "\'$!\'"); | 
|---|
| 673 |       exit(-1); | 
|---|
| 674 |     } | 
|---|
| 675 |  | 
|---|
| 676 |     # Fork a child to execute the ping to the current host to be added. | 
|---|
| 677 |     ADDFORK: { | 
|---|
| 678 |  | 
|---|
| 679 |       if ($pid{$host} = fork) { | 
|---|
| 680 |  | 
|---|
| 681 |         # parent code - | 
|---|
| 682 |         # close unneeded ends of pipes | 
|---|
| 683 |         # parent will wait for child processes if fanout limit reached | 
|---|
| 684 |  | 
|---|
| 685 |         close($Wout{$host}); | 
|---|
| 686 |         close($Werr{$host}); | 
|---|
| 687 |  | 
|---|
| 688 |         if (++$cur_fanout >= $fanval) { | 
|---|
| 689 |           &wait_for_kids_and_add_hosts(false); | 
|---|
| 690 |         } | 
|---|
| 691 |  | 
|---|
| 692 |       } elsif (defined $pid{$host}) { | 
|---|
| 693 |  | 
|---|
| 694 |         # child code - | 
|---|
| 695 |         # close unneeded ends of pipes | 
|---|
| 696 |         # redirect stdout and stderr to output pipes | 
|---|
| 697 |         # exec the ping command | 
|---|
| 698 |         # stdout/stderr will go to pipes to be read by parent | 
|---|
| 699 |  | 
|---|
| 700 |         close($Rout{$host}); | 
|---|
| 701 |         close($Rerr{$host}); | 
|---|
| 702 |  | 
|---|
| 703 |         # If the -v flag was specified, check whether the host can be ping'd. | 
|---|
| 704 |         # If the 1st ping fails, try a few more times to avoid false node down. | 
|---|
| 705 |         if ($verify) { | 
|---|
| 706 |           $pingCount = 0; | 
|---|
| 707 |           $pingRc = 1; | 
|---|
| 708 |           while ($pingRc != 0 && ++$pingCount <= $maxPingCount) { | 
|---|
| 709 |             `$ping -w $pingTimeout -c 1 $host 2>/dev/null`; | 
|---|
| 710 |             $pingRc = $? >> 8; | 
|---|
| 711 |             if ($pingRc > 0 && $iflag) { | 
|---|
| 712 |               printf STDERR "ping %s failed (%s); pingRc=%s\n", $host, $pingCount, $pingRc; | 
|---|
| 713 |             } | 
|---|
| 714 |             ++$pingTimeout; | 
|---|
| 715 |           } | 
|---|
| 716 |         } | 
|---|
| 717 |  | 
|---|
| 718 |         unless (open(STDOUT, ">&$Wout{$host}")) { | 
|---|
| 719 |           #die "mmdsh: Cannot redirect STDOUT: $!\n"; | 
|---|
| 720 |           &prtMsg(369, 'STDOUT', "\'$!\'"); | 
|---|
| 721 |           exit(-1); | 
|---|
| 722 |         } | 
|---|
| 723 |         unless (open(STDERR, ">&$Werr{$host}")) { | 
|---|
| 724 |           #die "mmdsh: Cannot redirect STDERR: $!\n"; | 
|---|
| 725 |           &prtMsg(369, 'STDERR', "\'$!\'"); | 
|---|
| 726 |           exit(-1); | 
|---|
| 727 |         } | 
|---|
| 728 |  | 
|---|
| 729 |         select(STDOUT); $| = 1; | 
|---|
| 730 |         select(STDERR); $| = 1; | 
|---|
| 731 |  | 
|---|
| 732 |         exit($pingRc); | 
|---|
| 733 |  | 
|---|
| 734 |       } else { | 
|---|
| 735 |  | 
|---|
| 736 |         # Try again.  The fork must have failed due to a resource problem. | 
|---|
| 737 |  | 
|---|
| 738 |         sleep 5; | 
|---|
| 739 |         redo ADDFORK; | 
|---|
| 740 |       } | 
|---|
| 741 |     } | 
|---|
| 742 |   } | 
|---|
| 743 |  | 
|---|
| 744 |   # Parent continues here after forking all the children for this command. | 
|---|
| 745 |   # Get the results of any remaining ping's (the number of hosts in the | 
|---|
| 746 |   # working collective may not be a multiple of the fanout value). | 
|---|
| 747 |   # Get rid of any hosts that have failed, reporting all removed hosts as | 
|---|
| 748 |   # directed by the [-R reportfile] and [-r] flags. | 
|---|
| 749 |   &wait_for_kids_and_add_hosts(true); | 
|---|
| 750 |   if ($reportFile && ($#goners >= 0)) { | 
|---|
| 751 |     # Write removed hosts to specified file.  The file is not created if | 
|---|
| 752 |     # the goners array is empty (i.e., $#goners = -1). | 
|---|
| 753 |     open(REPORTFILE, ">$reportFile"); | 
|---|
| 754 |     foreach $child_host (@goners) { | 
|---|
| 755 |       print REPORTFILE "$child_host\n"; | 
|---|
| 756 |     } | 
|---|
| 757 |     close(REPORTFILE); | 
|---|
| 758 |   } | 
|---|
| 759 |   if ($rflag) { | 
|---|
| 760 |     # Write removed hosts to standard error. | 
|---|
| 761 |     foreach $child_host (@goners) { | 
|---|
| 762 |       print STDERR "$child_host\n"; | 
|---|
| 763 |     } | 
|---|
| 764 |   } | 
|---|
| 765 |   &delete_hosts; | 
|---|
| 766 |   unless ($done) { | 
|---|
| 767 |     $cur_fanout = 0; | 
|---|
| 768 |     &check_wc; | 
|---|
| 769 |   } | 
|---|
| 770 |  | 
|---|
| 771 | }  #---------- end of add_wc_parallel routine ---------------------------- | 
|---|
| 772 |  | 
|---|
| 773 |  | 
|---|
| 774 | #---------------------------------------------------------------------------- | 
|---|
| 775 | # | 
|---|
| 776 | # parse | 
|---|
| 777 | # | 
|---|
| 778 | # Parse the command line. | 
|---|
| 779 | # | 
|---|
| 780 | #---------------------------------------------------------------------------- | 
|---|
| 781 |  | 
|---|
| 782 | sub parse { | 
|---|
| 783 |  | 
|---|
| 784 |    local(@indices,@temp,$Findex,$findex,$Iindex,$Lindex,$Nindex); | 
|---|
| 785 |    local($fn,$wfile,$host,@hostlist,$ht,$hl,$Narg,$nodesToUse); | 
|---|
| 786 |  | 
|---|
| 787 |    if ($ARGV[0] eq "-\?") { | 
|---|
| 788 |       &display_help; | 
|---|
| 789 |       exit; | 
|---|
| 790 |    } | 
|---|
| 791 |  | 
|---|
| 792 |    while ($ARGV[0] =~ /^-/) {    # while current parm starts with "-" | 
|---|
| 793 |  | 
|---|
| 794 |       if ($ARGV[0] =~ /[FfILNR](\S+)/) { # if flag is one of F, f, I, L, N, or R | 
|---|
| 795 |                                          # and there is no whitespace | 
|---|
| 796 |                                          # immediately after the flag | 
|---|
| 797 |          $Findex = index($ARGV[0],"F"); | 
|---|
| 798 |          $findex = index($ARGV[0],"f"); | 
|---|
| 799 |          $Iindex = index($ARGV[0],"I"); | 
|---|
| 800 |          $Lindex = index($ARGV[0],"L"); | 
|---|
| 801 |          $Nindex = index($ARGV[0],"N"); | 
|---|
| 802 |          $Rindex = index($ARGV[0],"R"); | 
|---|
| 803 |          @indices = ($Findex, $findex, $Iindex, $Lindex, $Nindex, $Rindex); | 
|---|
| 804 |  | 
|---|
| 805 |          @indices = sort @indices; | 
|---|
| 806 |          @temp = @indices; | 
|---|
| 807 |          foreach (@temp) {            # loop moves parm pos value to indices[0] | 
|---|
| 808 |             $_ == -1 && shift(@indices); | 
|---|
| 809 |          } | 
|---|
| 810 |  | 
|---|
| 811 |          if ($indices[0] == $Findex) {  # if the flag was "F" | 
|---|
| 812 |             if (!$fn) { | 
|---|
| 813 |                $fn = $1; | 
|---|
| 814 |                unless ($wfile = $fn) { | 
|---|
| 815 |                   #die "mmdsh: Missing argument\n"; | 
|---|
| 816 |                   &prtMsg(204, "-F"); | 
|---|
| 817 |                   &display_help; | 
|---|
| 818 |                   exit(-1); | 
|---|
| 819 |                } | 
|---|
| 820 |             } else { | 
|---|
| 821 |                #die "mmdsh:  F flag specified twice.\n"; | 
|---|
| 822 |                &prtMsg(36, "F"); | 
|---|
| 823 |                &display_help; | 
|---|
| 824 |                exit(-1); | 
|---|
| 825 |             } | 
|---|
| 826 |  | 
|---|
| 827 |          } elsif ($indices[0] == $findex) {  # if the flag was "f" | 
|---|
| 828 |             if (!$fanout) { | 
|---|
| 829 |                $fanout = $1; | 
|---|
| 830 |                if ($fanout =~ /\D/) { | 
|---|
| 831 |                   #die "mmdsh: Incorrect argument - $fanout\n"; | 
|---|
| 832 |                   &prtMsg(40, "-f", $fanout); | 
|---|
| 833 |                   &display_help; | 
|---|
| 834 |                   exit(-1); | 
|---|
| 835 |                } | 
|---|
| 836 |             } else { | 
|---|
| 837 |                #die "mmdsh:  f flag specified twice.\n"; | 
|---|
| 838 |                &prtMsg(36, "f"); | 
|---|
| 839 |                &display_help; | 
|---|
| 840 |                exit(-1); | 
|---|
| 841 |             } | 
|---|
| 842 |  | 
|---|
| 843 |          } elsif ($indices[0] == $Iindex) {  # if the flag was "I" | 
|---|
| 844 |             if (!$stageFile) { | 
|---|
| 845 |                $stageFile = $1; | 
|---|
| 846 |                unless ($fileToCopy = $stageFile) { | 
|---|
| 847 |                   #die "mmdsh: Missing argument\n"; | 
|---|
| 848 |                   &prtMsg(204, "-I"); | 
|---|
| 849 |                   &display_help; | 
|---|
| 850 |                   exit(-1); | 
|---|
| 851 |                } | 
|---|
| 852 |             } elsif (!$stageFile2) { | 
|---|
| 853 |                $stageFile2 = $1; | 
|---|
| 854 |                unless ($fileToCopy2 = $stageFile2) { | 
|---|
| 855 |                   #die "mmdsh: Missing argument\n"; | 
|---|
| 856 |                   &prtMsg(204, "-I"); | 
|---|
| 857 |                   &display_help; | 
|---|
| 858 |                   exit(-1); | 
|---|
| 859 |                } | 
|---|
| 860 |             } else { | 
|---|
| 861 |                #die "mmdsh:  I flag specified twice.\n"; | 
|---|
| 862 |                &prtMsg(36, "I"); | 
|---|
| 863 |                &display_help; | 
|---|
| 864 |                exit(-1); | 
|---|
| 865 |             } | 
|---|
| 866 |  | 
|---|
| 867 |          } elsif ($indices[0] == $Lindex) {  # if the flag was "L" | 
|---|
| 868 |             if (!$hl) { | 
|---|
| 869 |                $hl = $1; | 
|---|
| 870 |                if ($hl =~ /^,|,,|,$/) { | 
|---|
| 871 |                   #die "Incorrect argument - $hl\n"; | 
|---|
| 872 |                   &prtMsg(153, "-L"); | 
|---|
| 873 |                   &display_help; | 
|---|
| 874 |                   exit(-1); | 
|---|
| 875 |                } | 
|---|
| 876 |                if ($hl eq "-") { | 
|---|
| 877 |                   # Get names from stdin | 
|---|
| 878 |                   while (<STDIN>) { | 
|---|
| 879 |                      /^\s*#/ && next; | 
|---|
| 880 |                      /^\s*$/ && next; | 
|---|
| 881 |                      /;/ && next; | 
|---|
| 882 |                      /\S+ \S+/ && next; | 
|---|
| 883 |                      s/ //g; | 
|---|
| 884 |                      chop; | 
|---|
| 885 |                      push(@hostlist,$_); | 
|---|
| 886 |                   } | 
|---|
| 887 |                } else { | 
|---|
| 888 |                   @hostlist = split(/,/,$hl); | 
|---|
| 889 |                } | 
|---|
| 890 |             } else { | 
|---|
| 891 |                #die "mmdsh:  L flag specified twice.\n"; | 
|---|
| 892 |                &prtMsg(36, "L"); | 
|---|
| 893 |                &display_help; | 
|---|
| 894 |                exit(-1); | 
|---|
| 895 |             } | 
|---|
| 896 |  | 
|---|
| 897 |          } elsif ($indices[0] == $Nindex) {  # if the flag was "N" | 
|---|
| 898 |             if (!$Narg) { | 
|---|
| 899 |                $Narg = $1; | 
|---|
| 900 |                unless ($nodesToUse = $Narg) { | 
|---|
| 901 |                   #die "mmdsh: Missing argument\n"; | 
|---|
| 902 |                   &prtMsg(204, "-N"); | 
|---|
| 903 |                   &display_help; | 
|---|
| 904 |                   exit(-1); | 
|---|
| 905 |                } | 
|---|
| 906 |             } else { | 
|---|
| 907 |                #die "mmdsh:  N flag specified twice.\n"; | 
|---|
| 908 |                &prtMsg(36, "N"); | 
|---|
| 909 |                &display_help; | 
|---|
| 910 |                exit(-1); | 
|---|
| 911 |             } | 
|---|
| 912 |  | 
|---|
| 913 |          } elsif ($indices[0] == $Rindex) {  # if the flag was "R" | 
|---|
| 914 |             if (!$reportFile) { | 
|---|
| 915 |                unless ($reportFile = $1) { | 
|---|
| 916 |                   #die "mmdsh: Missing argument\n"; | 
|---|
| 917 |                   &prtMsg(204, "-R"); | 
|---|
| 918 |                   &display_help; | 
|---|
| 919 |                   exit(-1); | 
|---|
| 920 |                } | 
|---|
| 921 |             } else { | 
|---|
| 922 |                #die "mmdsh:  R flag specified twice.\n"; | 
|---|
| 923 |                &prtMsg(36, "R"); | 
|---|
| 924 |                &display_help; | 
|---|
| 925 |                exit(-1); | 
|---|
| 926 |             } | 
|---|
| 927 |          } | 
|---|
| 928 |          $ARGV[0] = substr($ARGV[0], 0, $indices[0] + 1); | 
|---|
| 929 |  | 
|---|
| 930 |       } elsif ($ARGV[0] =~ /F$/) {  # otherwise, if the flag is an "F" | 
|---|
| 931 |                                     #  followed by whitespace | 
|---|
| 932 |          if (!$fn) { | 
|---|
| 933 |             $fn = $ARGV[1]; | 
|---|
| 934 |             unless ($wfile = $fn) { | 
|---|
| 935 |                #die "mmdsh: Missing argument\n"; | 
|---|
| 936 |                &prtMsg(204, "-F"); | 
|---|
| 937 |                &display_help; | 
|---|
| 938 |                exit(-1); | 
|---|
| 939 |             } | 
|---|
| 940 |             $shiftflag++; | 
|---|
| 941 |          } else { | 
|---|
| 942 |             #die "mmdsh:  F flag specified twice.\n"; | 
|---|
| 943 |             &prtMsg(36, "F"); | 
|---|
| 944 |             &display_help; | 
|---|
| 945 |             exit(-1); | 
|---|
| 946 |          } | 
|---|
| 947 |  | 
|---|
| 948 |       } elsif ($ARGV[0] =~ /f$/) {  # otherwise, if the flag is an "f" | 
|---|
| 949 |                                     #  followed by whitespace | 
|---|
| 950 |          if (!$fanout) { | 
|---|
| 951 |             $fanout = $ARGV[1]; | 
|---|
| 952 |             unless ($fanout) { | 
|---|
| 953 |                #die "mmdsh: Missing argument\n"; | 
|---|
| 954 |                &prtMsg(204, "-f"); | 
|---|
| 955 |                &display_help; | 
|---|
| 956 |                exit(-1); | 
|---|
| 957 |             } | 
|---|
| 958 |             if ($fanout =~ /\D/) { | 
|---|
| 959 |                #die "mmdsh: Incorrect argument - $fanout\n"; | 
|---|
| 960 |                &prtMsg(40, "-f", $fanout); | 
|---|
| 961 |                &display_help; | 
|---|
| 962 |                exit(-1); | 
|---|
| 963 |             } | 
|---|
| 964 |             $shiftflag++; | 
|---|
| 965 |          } else { | 
|---|
| 966 |             #die "mmdsh:  f flag specified twice.\n"; | 
|---|
| 967 |             &prtMsg(36, "f"); | 
|---|
| 968 |             &display_help; | 
|---|
| 969 |             exit(-1); | 
|---|
| 970 |          } | 
|---|
| 971 |  | 
|---|
| 972 |       } elsif ($ARGV[0] =~ /I$/) {  # otherwise, if the flag is an "I" | 
|---|
| 973 |                                     #  followed by whitespace | 
|---|
| 974 |          if (!$stageFile) { | 
|---|
| 975 |             $stageFile = $ARGV[1]; | 
|---|
| 976 |             unless ($fileToCopy = $stageFile) { | 
|---|
| 977 |                #die "mmdsh: Missing argument\n"; | 
|---|
| 978 |                &prtMsg(204, "-I"); | 
|---|
| 979 |                &display_help; | 
|---|
| 980 |                exit(-1); | 
|---|
| 981 |             } | 
|---|
| 982 |             $shiftflag++; | 
|---|
| 983 |          } elsif (!$stageFile2) { | 
|---|
| 984 |             $stageFile2 = $ARGV[1]; | 
|---|
| 985 |             unless ($fileToCopy2 = $stageFile2) { | 
|---|
| 986 |                #die "mmdsh: Missing argument\n"; | 
|---|
| 987 |                &prtMsg(204, "-I"); | 
|---|
| 988 |                &display_help; | 
|---|
| 989 |                exit(-1); | 
|---|
| 990 |             } | 
|---|
| 991 |             $shiftflag++; | 
|---|
| 992 |          } else { | 
|---|
| 993 |             #die "mmdsh:  I flag specified twice.\n"; | 
|---|
| 994 |             &prtMsg(36, "I"); | 
|---|
| 995 |             &display_help; | 
|---|
| 996 |             exit(-1); | 
|---|
| 997 |          } | 
|---|
| 998 |  | 
|---|
| 999 |       } elsif ($ARGV[0] =~ /L$/) {  # otherwise, if the flag is an "L" | 
|---|
| 1000 |                                     #  followed by whitespace | 
|---|
| 1001 |          if (!$hl) { | 
|---|
| 1002 |             $hl = $ARGV[1]; | 
|---|
| 1003 |             unless ($hl) { | 
|---|
| 1004 |               #die "mmdsh: Missing argument\n"; | 
|---|
| 1005 |                &prtMsg(204, "-L"); | 
|---|
| 1006 |                &display_help; | 
|---|
| 1007 |                exit(-1); | 
|---|
| 1008 |             } | 
|---|
| 1009 |             if ($hl =~ /^,|,,|,$/) { | 
|---|
| 1010 |                #die "Incorrect argument - $hl\n"; | 
|---|
| 1011 |                &prtMsg(153, "-L"); | 
|---|
| 1012 |                &display_help; | 
|---|
| 1013 |                exit(-1); | 
|---|
| 1014 |             } | 
|---|
| 1015 |             if ($hl eq "-") { | 
|---|
| 1016 |                while (<STDIN>) { | 
|---|
| 1017 |                   /^\s*#/ && next; | 
|---|
| 1018 |                   /^\s*$/ && next; | 
|---|
| 1019 |                   /;/ && next; | 
|---|
| 1020 |                   /\S+ \S+/ && next; | 
|---|
| 1021 |                   s/ //g; | 
|---|
| 1022 |                   chop; | 
|---|
| 1023 |                   push(@hostlist,$_); | 
|---|
| 1024 |                } | 
|---|
| 1025 |             } else { | 
|---|
| 1026 |                @hostlist = split(/,/,$hl); | 
|---|
| 1027 |             } | 
|---|
| 1028 |             $shiftflag++; | 
|---|
| 1029 |          } else { | 
|---|
| 1030 |             #die "mmdsh:  L flag specified twice.\n"; | 
|---|
| 1031 |             &prtMsg(36, "L"); | 
|---|
| 1032 |             &display_help; | 
|---|
| 1033 |             exit(-1); | 
|---|
| 1034 |          } | 
|---|
| 1035 |  | 
|---|
| 1036 |       } elsif ($ARGV[0] =~ /N$/) {  # otherwise, if the flag is an "N" | 
|---|
| 1037 |                                     #  followed by whitespace | 
|---|
| 1038 |          if (!$Narg) { | 
|---|
| 1039 |             $Narg = $ARGV[1]; | 
|---|
| 1040 |             unless ($nodesToUse = $Narg) { | 
|---|
| 1041 |                #die "mmdsh: Missing argument\n"; | 
|---|
| 1042 |                &prtMsg(204, "-N"); | 
|---|
| 1043 |                &display_help; | 
|---|
| 1044 |                exit(-1); | 
|---|
| 1045 |             } | 
|---|
| 1046 |             $shiftflag++; | 
|---|
| 1047 |          } else { | 
|---|
| 1048 |             #die "mmdsh:  N flag specified twice.\n"; | 
|---|
| 1049 |             &prtMsg(36, "N"); | 
|---|
| 1050 |             &display_help; | 
|---|
| 1051 |             exit(-1); | 
|---|
| 1052 |          } | 
|---|
| 1053 |  | 
|---|
| 1054 |       } elsif ($ARGV[0] =~ /R$/) {  # otherwise, if the flag is an "R" | 
|---|
| 1055 |                                     #  followed by whitespace | 
|---|
| 1056 |          if (!$reportFile) { | 
|---|
| 1057 |             unless ($reportFile = $ARGV[1]) { | 
|---|
| 1058 |               #die "mmdsh: Missing argument\n"; | 
|---|
| 1059 |               &prtMsg(204, "-R"); | 
|---|
| 1060 |               &display_help; | 
|---|
| 1061 |               exit(-1); | 
|---|
| 1062 |             } | 
|---|
| 1063 |             $shiftflag++; | 
|---|
| 1064 |          } else { | 
|---|
| 1065 |             #die "mmdsh:  R flag specified twice.\n"; | 
|---|
| 1066 |             &prtMsg(36, "R"); | 
|---|
| 1067 |             &display_help; | 
|---|
| 1068 |             exit(-1); | 
|---|
| 1069 |          } | 
|---|
| 1070 |       }  # end of if ($ARGV[0] =~ /[FfILNR](\S+)/) | 
|---|
| 1071 |  | 
|---|
| 1072 |       if (index($ARGV[0], 'i') >= $[) {   # if there is an "i" flag present | 
|---|
| 1073 |          if (rindex($ARGV[0], 'i') == index($ARGV[0], 'i')) { | 
|---|
| 1074 |             if ($iflag++) { | 
|---|
| 1075 |                #die "mmdsh:  i flag specified twice.\n"; | 
|---|
| 1076 |                &prtMsg(36, "i"); | 
|---|
| 1077 |                &display_help; | 
|---|
| 1078 |                exit(-1); | 
|---|
| 1079 |             } | 
|---|
| 1080 |          } else { | 
|---|
| 1081 |             #die "mmdsh:  i flag specified twice.\n"; | 
|---|
| 1082 |             &prtMsg(36, "i"); | 
|---|
| 1083 |             &display_help; | 
|---|
| 1084 |             exit(-1); | 
|---|
| 1085 |          } | 
|---|
| 1086 |       } | 
|---|
| 1087 |  | 
|---|
| 1088 |       if (index($ARGV[0], 'k') >= $[) {   # if there is a "k" flag present | 
|---|
| 1089 |          if (rindex($ARGV[0], 'k') == index($ARGV[0], 'k')) { | 
|---|
| 1090 |             if ($kflag++) { | 
|---|
| 1091 |                #die "mmdsh:  k flag specified twice.\n"; | 
|---|
| 1092 |                &prtMsg(36, "k"); | 
|---|
| 1093 |                &display_help; | 
|---|
| 1094 |                exit(-1); | 
|---|
| 1095 |             } | 
|---|
| 1096 |          } else { | 
|---|
| 1097 |             #die "mmdsh:  k flag specified twice.\n"; | 
|---|
| 1098 |             &prtMsg(36, "k"); | 
|---|
| 1099 |             &display_help; | 
|---|
| 1100 |             exit(-1); | 
|---|
| 1101 |          } | 
|---|
| 1102 |       } | 
|---|
| 1103 |  | 
|---|
| 1104 |       if (index($ARGV[0], 'r') >= $[) {   # if there is an "r" flag present | 
|---|
| 1105 |          if (rindex($ARGV[0], 'r') == index($ARGV[0], 'r')) { | 
|---|
| 1106 |             if ($rflag++) { | 
|---|
| 1107 |                #die "mmdsh:  r flag specified twice.\n"; | 
|---|
| 1108 |                &prtMsg(36, "r"); | 
|---|
| 1109 |                &display_help; | 
|---|
| 1110 |                exit(-1); | 
|---|
| 1111 |             } | 
|---|
| 1112 |          } else { | 
|---|
| 1113 |             #die "mmdsh:  r flag specified twice.\n"; | 
|---|
| 1114 |             &prtMsg(36, "r"); | 
|---|
| 1115 |             &display_help; | 
|---|
| 1116 |             exit(-1); | 
|---|
| 1117 |          } | 
|---|
| 1118 |       } | 
|---|
| 1119 |  | 
|---|
| 1120 |       if (index($ARGV[0], 's') >= $[) {   # if there is an "s" flag present | 
|---|
| 1121 |          if (rindex($ARGV[0], 's') == index($ARGV[0], 's')) { | 
|---|
| 1122 |             if ($sflag++) { | 
|---|
| 1123 |                #die "mmdsh:  s flag specified twice.\n"; | 
|---|
| 1124 |                &prtMsg(36, "s"); | 
|---|
| 1125 |                &display_help; | 
|---|
| 1126 |                exit(-1); | 
|---|
| 1127 |             } | 
|---|
| 1128 |          } else { | 
|---|
| 1129 |             #die "mmdsh:  s flag specified twice.\n"; | 
|---|
| 1130 |             &prtMsg(36, "s"); | 
|---|
| 1131 |             &display_help; | 
|---|
| 1132 |             exit(-1); | 
|---|
| 1133 |          } | 
|---|
| 1134 |       } | 
|---|
| 1135 |  | 
|---|
| 1136 |       if (index($ARGV[0], 'v') >= $[) {   # if there is a "v" flag present | 
|---|
| 1137 |          if (rindex($ARGV[0], 'v') == index($ARGV[0], 'v')) { | 
|---|
| 1138 |             if ($verify++) { | 
|---|
| 1139 |                #die "mmdsh:  v flag specified twice.\n"; | 
|---|
| 1140 |                &prtMsg(36, "v"); | 
|---|
| 1141 |                &display_help; | 
|---|
| 1142 |                exit(-1); | 
|---|
| 1143 |             } | 
|---|
| 1144 |          } else { | 
|---|
| 1145 |             #die "mmdsh:  v flag specified twice.\n"; | 
|---|
| 1146 |             &prtMsg(36, "v"); | 
|---|
| 1147 |             &display_help; | 
|---|
| 1148 |             exit(-1); | 
|---|
| 1149 |          } | 
|---|
| 1150 |       } | 
|---|
| 1151 |  | 
|---|
| 1152 |       if ($ARGV[0] =~ /^-.*([^fFiIkLNRrsv]).*/) {  # fail if any unknown flags | 
|---|
| 1153 |          #die "mmdsh: Incorrect option - $1\n"; | 
|---|
| 1154 |          &prtMsg(13, $1); | 
|---|
| 1155 |          &display_help; | 
|---|
| 1156 |          exit(-1); | 
|---|
| 1157 |       } | 
|---|
| 1158 |  | 
|---|
| 1159 |       if ($ARGV[0] =~ /^-$/) {                   # fail if no flag after "-" | 
|---|
| 1160 |          #die "mmdsh: Missing option\n"; | 
|---|
| 1161 |          &prtMsg(168); | 
|---|
| 1162 |          &display_help; | 
|---|
| 1163 |          exit(-1); | 
|---|
| 1164 |       } | 
|---|
| 1165 |  | 
|---|
| 1166 |       shift(@ARGV);      # shift to next parameter | 
|---|
| 1167 |       if ($shiftflag) { | 
|---|
| 1168 |          shift(@ARGV);   # shift again if parameter pertains to previous flag | 
|---|
| 1169 |          $shiftflag--;   # reset the shift flag | 
|---|
| 1170 |       } | 
|---|
| 1171 |    } | 
|---|
| 1172 |  | 
|---|
| 1173 |    # Process any hosts that were specified via the -L flag. | 
|---|
| 1174 |    if (@hostlist) { | 
|---|
| 1175 |       $wfound++; | 
|---|
| 1176 |       # If the -v flag was specified, call routine to | 
|---|
| 1177 |       # only add pingable hosts; otherwise, add them all. | 
|---|
| 1178 |       if ($verify) { | 
|---|
| 1179 |          # Put the hosts specified by the "L" flag into a temporary file. | 
|---|
| 1180 |          $hlfile = "/var/mmfs/tmp/hostlistFile.mmdsh.$$"; | 
|---|
| 1181 |          open(HLFILE, ">$hlfile"); | 
|---|
| 1182 |          foreach $ht (@hostlist) { | 
|---|
| 1183 |             print HLFILE "$ht\n"; | 
|---|
| 1184 |             $hostCount++; | 
|---|
| 1185 |             $targetHost = $ht; | 
|---|
| 1186 |          } | 
|---|
| 1187 |          close(HLFILE); | 
|---|
| 1188 |  | 
|---|
| 1189 |          # Pass the created file to routine that only adds pingable hosts. | 
|---|
| 1190 |          # The temp file is cleaned up inside the add_wc_parallel routine. | 
|---|
| 1191 |          unless (open(HLFILE, "$hlfile")) { | 
|---|
| 1192 |             #die "mmdsh: Cannot open hostlist file $hlfile: $!\n"; | 
|---|
| 1193 |             &prtMsg(364, $hlfile, "\'$!\'"); | 
|---|
| 1194 |             `/bin/rm -f $hlfile`; | 
|---|
| 1195 |             exit(-1); | 
|---|
| 1196 |          } | 
|---|
| 1197 |          &add_wc_parallel(HLFILE); | 
|---|
| 1198 |          close(HLFILE); | 
|---|
| 1199 |          `/bin/rm -f $hlfile`; | 
|---|
| 1200 |  | 
|---|
| 1201 |       } else { | 
|---|
| 1202 |          foreach $ht (@hostlist) {  # add any hosts specified by the "L" flag | 
|---|
| 1203 |             &add_wc($ht); | 
|---|
| 1204 |             $hostCount++; | 
|---|
| 1205 |             $targetHost = $ht; | 
|---|
| 1206 |          } | 
|---|
| 1207 |       } | 
|---|
| 1208 |    } | 
|---|
| 1209 |  | 
|---|
| 1210 |    # Process any hosts that were specified via the -F flag. | 
|---|
| 1211 |    if ($wfile) { | 
|---|
| 1212 |       $wfound++; | 
|---|
| 1213 |       unless (open(WCFILE, $wfile)) { | 
|---|
| 1214 |          #die "mmdsh: Cannot open working collective file $wfile: $!\n"; | 
|---|
| 1215 |          &prtMsg(364, $wfile, "\'$!\'"); | 
|---|
| 1216 |          exit(-1); | 
|---|
| 1217 |       } | 
|---|
| 1218 |       # If the -v flag was specified, call routine to | 
|---|
| 1219 |       # only add pingable hosts; otherwise, add them all. | 
|---|
| 1220 |       if ($verify) { | 
|---|
| 1221 |          &add_wc_parallel(WCFILE); | 
|---|
| 1222 |       } else { | 
|---|
| 1223 |          while ($new_host = <WCFILE>) { | 
|---|
| 1224 |             $new_host =~ /^\s*#/ && next; | 
|---|
| 1225 |             $new_host =~ /^\s*$/ && next; | 
|---|
| 1226 |             $new_host =~ /;/ && next; | 
|---|
| 1227 |             $new_host =~ /\S+\s+\S+/ && next; | 
|---|
| 1228 |             chop($new_host); | 
|---|
| 1229 |             &add_wc($new_host); | 
|---|
| 1230 |          } | 
|---|
| 1231 |       } | 
|---|
| 1232 |       close(WCFILE); | 
|---|
| 1233 |    } | 
|---|
| 1234 |  | 
|---|
| 1235 |    # Process any nodes that were specified via the -N flag. | 
|---|
| 1236 |    if ($nodesToUse) { | 
|---|
| 1237 |       # Convert the node specification into a verified file of nodes. | 
|---|
| 1238 |       $hlfile = "/var/mmfs/tmp/hostlistFile.mmdsh.$$"; | 
|---|
| 1239 |       $cmd = "$MMCOMMON run createVerifiedNodefile $nodesToUse $REL_HOSTNAME_Field no $hlfile"; | 
|---|
| 1240 |       if ($rc = system($cmd)) | 
|---|
| 1241 |       { | 
|---|
| 1242 |          $rc = &normalizeRC($rc); | 
|---|
| 1243 |          &prtMsg(206, $rc); | 
|---|
| 1244 |          `/bin/rm -f $hlfile`; | 
|---|
| 1245 |          exit(-1); | 
|---|
| 1246 |       } | 
|---|
| 1247 |  | 
|---|
| 1248 |       # Process the nodes in the file that was created. | 
|---|
| 1249 |       if ($hlfile) { | 
|---|
| 1250 |          $wfound++; | 
|---|
| 1251 |          unless (open(HLFILE, $hlfile)) { | 
|---|
| 1252 |             #die "mmdsh: Cannot open node file $hlfile: $!\n"; | 
|---|
| 1253 |             &prtMsg(364, $hlfile, "\'$!\'"); | 
|---|
| 1254 |             exit(-1); | 
|---|
| 1255 |          } | 
|---|
| 1256 |          # If the -v flag was specified, call routine to | 
|---|
| 1257 |          # only add pingable hosts; otherwise, add them all. | 
|---|
| 1258 |          if ($verify) { | 
|---|
| 1259 |             &add_wc_parallel(HLFILE); | 
|---|
| 1260 |          } else { | 
|---|
| 1261 |             while ($new_host = <HLFILE>) { | 
|---|
| 1262 |                $new_host =~ /^\s*#/ && next; | 
|---|
| 1263 |                $new_host =~ /^\s*$/ && next; | 
|---|
| 1264 |                $new_host =~ /;/ && next; | 
|---|
| 1265 |                $new_host =~ /\S+\s+\S+/ && next; | 
|---|
| 1266 |                chop($new_host); | 
|---|
| 1267 |                &add_wc($new_host); | 
|---|
| 1268 |             } | 
|---|
| 1269 |          } | 
|---|
| 1270 |          close(HLFILE); | 
|---|
| 1271 |          `/bin/rm -f $hlfile`; | 
|---|
| 1272 |       } | 
|---|
| 1273 |    } | 
|---|
| 1274 |  | 
|---|
| 1275 |    # Verify the files to be staged exist and are in a subdir of /var/mmfs. | 
|---|
| 1276 |    if ($stageFile) { | 
|---|
| 1277 |      unless ( $fileToCopy =~ /^\/var\/mmfs\//) { | 
|---|
| 1278 |        die "mmdsh: Files may only be copied to /var/mmfs.\n"; | 
|---|
| 1279 |      } | 
|---|
| 1280 |      unless ( -f $fileToCopy ) { | 
|---|
| 1281 |        #die "mmdsh: File $fileToCopy not found\n"; | 
|---|
| 1282 |        &prtMsg(364, $fileToCopy, "\'$!\'"); | 
|---|
| 1283 |        exit(-1); | 
|---|
| 1284 |      } | 
|---|
| 1285 |    } | 
|---|
| 1286 |  | 
|---|
| 1287 |    if ($stageFile2) { | 
|---|
| 1288 |      unless ( $fileToCopy2 =~ /^\/var\/mmfs\//) { | 
|---|
| 1289 |        die "mmdsh: Files may only be copied to /var/mmfs.\n"; | 
|---|
| 1290 |      } | 
|---|
| 1291 |      unless ( -f $fileToCopy2 ) { | 
|---|
| 1292 |        #die "mmdsh: File $fileToCopy2 not found\n"; | 
|---|
| 1293 |        &prtMsg(364, $fileToCopy2, "\'$!\'"); | 
|---|
| 1294 |        exit(-1); | 
|---|
| 1295 |      } | 
|---|
| 1296 |    } | 
|---|
| 1297 |  | 
|---|
| 1298 | }  #---------- end of parse routine ------------------------------------ | 
|---|
| 1299 |  | 
|---|
| 1300 |  | 
|---|
| 1301 | #---------------------------------------------------------------------------- | 
|---|
| 1302 | # | 
|---|
| 1303 | # set_defaults | 
|---|
| 1304 | # | 
|---|
| 1305 | # Set default values for those values that have not been specified. | 
|---|
| 1306 | # If fanout was not specified, it is set to the default fanout value. | 
|---|
| 1307 | # If login name was not specified, it is set to that of the current user. | 
|---|
| 1308 | # | 
|---|
| 1309 | #---------------------------------------------------------------------------- | 
|---|
| 1310 |  | 
|---|
| 1311 | sub set_defaults { | 
|---|
| 1312 |  | 
|---|
| 1313 |   unless ($fanout) { | 
|---|
| 1314 |     unless ($fanout = $ENV{'FANOUT'}) { | 
|---|
| 1315 |       $fanout = $fanout_default; | 
|---|
| 1316 |     } | 
|---|
| 1317 |   } | 
|---|
| 1318 |   unless ($login) { | 
|---|
| 1319 |     $login = (getpwuid($<))[0]; | 
|---|
| 1320 |   } | 
|---|
| 1321 |  | 
|---|
| 1322 | }  #---------- end of set_defaults routine ----------------------------- | 
|---|
| 1323 |  | 
|---|
| 1324 |  | 
|---|
| 1325 | #---------------------------------------------------------------------------- | 
|---|
| 1326 | # | 
|---|
| 1327 | # readem | 
|---|
| 1328 | # | 
|---|
| 1329 | # Read the stdout and stderr pipes for all hosts in the current fanout. | 
|---|
| 1330 | # | 
|---|
| 1331 | #---------------------------------------------------------------------------- | 
|---|
| 1332 |  | 
|---|
| 1333 | sub readem { | 
|---|
| 1334 |  | 
|---|
| 1335 |   local(@h) = @_; | 
|---|
| 1336 |   local($host); | 
|---|
| 1337 |   foreach $host (@h) { | 
|---|
| 1338 |     &read_pipes_and_wait(true, $host); | 
|---|
| 1339 |   } | 
|---|
| 1340 |   @h = (); | 
|---|
| 1341 |  | 
|---|
| 1342 | }  #---------- end of readem routine --------------------------------- | 
|---|
| 1343 |  | 
|---|
| 1344 |  | 
|---|
| 1345 | #---------------------------------------------------------------------------- | 
|---|
| 1346 | # | 
|---|
| 1347 | # display_wc | 
|---|
| 1348 | # | 
|---|
| 1349 | # If requested by means of the -i option, display the set of nodes | 
|---|
| 1350 | # on which the command will be run. | 
|---|
| 1351 | # | 
|---|
| 1352 | #---------------------------------------------------------------------------- | 
|---|
| 1353 |  | 
|---|
| 1354 | sub display_wc { | 
|---|
| 1355 |  | 
|---|
| 1356 |   local($i); | 
|---|
| 1357 |   if ($iflag) { | 
|---|
| 1358 |     #print STDOUT "Nodes on which the command will be run:\n"; | 
|---|
| 1359 |     &prtMsg(362); | 
|---|
| 1360 |     $i = 0; | 
|---|
| 1361 |     while ($i <= $#wc) { | 
|---|
| 1362 |       printf STDERR "%-19.18s", $wc[$i]; | 
|---|
| 1363 |       printf STDERR "%-19.18s", $wc[$i+1]; | 
|---|
| 1364 |       printf STDERR "%-19.18s", $wc[$i+2]; | 
|---|
| 1365 |       printf STDERR "%-19.18s\n", $wc[$i+3]; | 
|---|
| 1366 |       $i = $i + 4; | 
|---|
| 1367 |     } | 
|---|
| 1368 |   } | 
|---|
| 1369 |  | 
|---|
| 1370 | }  #---------- end of display_wc routine ------------------------------- | 
|---|
| 1371 |  | 
|---|
| 1372 |  | 
|---|
| 1373 | #---------------------------------------------------------------------------- | 
|---|
| 1374 | # | 
|---|
| 1375 | # get_wc | 
|---|
| 1376 | # | 
|---|
| 1377 | # Determine the working collective, if not already obtained from command line. | 
|---|
| 1378 | # Look for filename in $WCOLL containing the hostnames, one per line. | 
|---|
| 1379 | # | 
|---|
| 1380 | #---------------------------------------------------------------------------- | 
|---|
| 1381 |  | 
|---|
| 1382 | sub get_wc { | 
|---|
| 1383 |  | 
|---|
| 1384 |   local($wfile,$new_host); | 
|---|
| 1385 |   if (!@wc && !$wfound) { | 
|---|
| 1386 |     unless ($wfile = $ENV{'WCOLL'}) { | 
|---|
| 1387 |       #die "mmdsh: Working collective environment variable not set\n"; | 
|---|
| 1388 |       &prtMsg(363); | 
|---|
| 1389 |       exit(-1); | 
|---|
| 1390 |     } | 
|---|
| 1391 |     unless (open(WCFILE, $wfile)) { | 
|---|
| 1392 |       #die "mmdsh: Cannot open working collective file $wfile: $!\n"; | 
|---|
| 1393 |       &prtMsg(364, $wfile, "\'$!\'"); | 
|---|
| 1394 |       exit(-1); | 
|---|
| 1395 |     } | 
|---|
| 1396 |     if ($verify) { | 
|---|
| 1397 |       &add_wc_parallel(WCFILE); | 
|---|
| 1398 |     } else { | 
|---|
| 1399 |       while ($new_host = <WCFILE>) { | 
|---|
| 1400 |         $new_host =~ /^\s*#/ && next; | 
|---|
| 1401 |         $new_host =~ /^\s*$/ && next; | 
|---|
| 1402 |         $new_host =~ /;/ && next; | 
|---|
| 1403 |         $new_host =~ /\S+\s+\S+/ && next; | 
|---|
| 1404 |         chop($new_host); | 
|---|
| 1405 |         &add_wc($new_host); | 
|---|
| 1406 |       } | 
|---|
| 1407 |     } | 
|---|
| 1408 |     close(WCFILE); | 
|---|
| 1409 |   } | 
|---|
| 1410 |  | 
|---|
| 1411 | }  #---------- end of get_wc routine ----------------------------------- | 
|---|
| 1412 |  | 
|---|
| 1413 |  | 
|---|
| 1414 | #---------------------------------------------------------------------------- | 
|---|
| 1415 | # | 
|---|
| 1416 | # set_signals | 
|---|
| 1417 | # | 
|---|
| 1418 | # HUP is ignored in the mmdsh parent and its exec'ed rsh children. | 
|---|
| 1419 | # | 
|---|
| 1420 | # STOP, CONT, and TSTP are defaulted - this means that they work on the | 
|---|
| 1421 | # parent, but are ignored (not propagated to) the exec'ed rsh children | 
|---|
| 1422 | # or the remote processes. | 
|---|
| 1423 | # | 
|---|
| 1424 | # Set the signal handler for all other signals. | 
|---|
| 1425 | # The signals will be propagated to the exec'd children and then | 
|---|
| 1426 | # the default action will be taken in the parent. | 
|---|
| 1427 | # | 
|---|
| 1428 | # rsh will propagate TERM, QUIT, and INT to the remote processes. | 
|---|
| 1429 | # | 
|---|
| 1430 | #---------------------------------------------------------------------------- | 
|---|
| 1431 |  | 
|---|
| 1432 | sub set_signals { | 
|---|
| 1433 |  | 
|---|
| 1434 |   # Default STOP, CONT, TSTP signal handling | 
|---|
| 1435 |   $SIG{'STOP'} = 'DEFAULT'; | 
|---|
| 1436 |   $SIG{'CONT'} = 'DEFAULT'; | 
|---|
| 1437 |   $SIG{'TSTP'} = 'DEFAULT'; | 
|---|
| 1438 |  | 
|---|
| 1439 |   # Propagate signals to forked kids. | 
|---|
| 1440 |   $SIG{'TERM'} = 'infanticide'; | 
|---|
| 1441 |   $SIG{'QUIT'} = 'infanticide'; | 
|---|
| 1442 |   $SIG{'INT'}  = 'infanticide'; | 
|---|
| 1443 |   $SIG{'ABRT'} = 'infanticide'; | 
|---|
| 1444 |   $SIG{'ALRM'} = 'infanticide'; | 
|---|
| 1445 |   $SIG{'FPE'}  = 'infanticide'; | 
|---|
| 1446 |   $SIG{'ILL'}  = 'infanticide'; | 
|---|
| 1447 |   $SIG{'PIPE'} = 'infanticide'; | 
|---|
| 1448 |   $SIG{'SEGV'} = 'infanticide'; | 
|---|
| 1449 |   $SIG{'USR1'} = 'infanticide'; | 
|---|
| 1450 |   $SIG{'USR2'} = 'infanticide'; | 
|---|
| 1451 |   $SIG{'TTIN'} = 'infanticide'; | 
|---|
| 1452 |   $SIG{'TTOU'} = 'infanticide'; | 
|---|
| 1453 |   $SIG{'BUS'}  = 'infanticide'; | 
|---|
| 1454 |  | 
|---|
| 1455 | }  #---------- end of set_signals routine ----------------------------- | 
|---|
| 1456 |  | 
|---|
| 1457 |  | 
|---|
| 1458 | #---------------------------------------------------------------------------- | 
|---|
| 1459 | # | 
|---|
| 1460 | # wait_for_kids_and_add_hosts | 
|---|
| 1461 | # | 
|---|
| 1462 | # When a child dies, it must be an exit after the end of his ping. | 
|---|
| 1463 | # If a negative return code, the ping failed.  Check whether we | 
|---|
| 1464 | # should give up on this host and eliminate him from the collective. | 
|---|
| 1465 | # Add the kid's host to the working collective if the ping succeeded | 
|---|
| 1466 | # or if we were told to add him anyway. | 
|---|
| 1467 | # | 
|---|
| 1468 | # Parameters: | 
|---|
| 1469 | #   wait_all -- true to "wait" on all active children, false to only "wait" | 
|---|
| 1470 | #               for completed children (fanout maintenance). | 
|---|
| 1471 | # | 
|---|
| 1472 | #---------------------------------------------------------------------------- | 
|---|
| 1473 |  | 
|---|
| 1474 | sub wait_for_kids_and_add_hosts { | 
|---|
| 1475 |  | 
|---|
| 1476 |   my $wait_all = shift; | 
|---|
| 1477 |  | 
|---|
| 1478 |   local($child_pid, $child_rc, $child_host, $host_found, $wait_opt); | 
|---|
| 1479 |  | 
|---|
| 1480 |   if ($wait_all eq true) { | 
|---|
| 1481 |     # Wait for all children ==> Blocking waitpid | 
|---|
| 1482 |     $wait_opt = 0; | 
|---|
| 1483 |   } | 
|---|
| 1484 |   else { | 
|---|
| 1485 |     # Wait for completed children only ==> Non-blocking waitpid | 
|---|
| 1486 |     $wait_opt = &WNOHANG; | 
|---|
| 1487 |   } | 
|---|
| 1488 |  | 
|---|
| 1489 |   # Wait for any children and process accordingly.  We will wait for at | 
|---|
| 1490 |   # least one child for both "wait some" and "wait all" cases as the design | 
|---|
| 1491 |   # point is to only call this routine when the fanout limit has been reached. | 
|---|
| 1492 |   if (($child_pid = wait) != -1) { | 
|---|
| 1493 |  | 
|---|
| 1494 |     PINGWAIT: { | 
|---|
| 1495 |  | 
|---|
| 1496 |       # Obtain the return code and hostname for the child process. | 
|---|
| 1497 |       $child_rc = $? >> 8; | 
|---|
| 1498 |       foreach (keys %pid) { | 
|---|
| 1499 |         if ($pid{$_} == $child_pid) { | 
|---|
| 1500 |           $child_host = $_; | 
|---|
| 1501 |           last; | 
|---|
| 1502 |         } | 
|---|
| 1503 |       } | 
|---|
| 1504 |  | 
|---|
| 1505 |       # Close the pipes used for collecting data from the ping. | 
|---|
| 1506 |       close($Rout{$child_host}); | 
|---|
| 1507 |       close($Rerr{$child_host}); | 
|---|
| 1508 |  | 
|---|
| 1509 |       # If the ping failed, assume the host is not reachable; | 
|---|
| 1510 |       #  don't add it to the collective unless told to include it anyway. | 
|---|
| 1511 |       if ($child_rc != 0) { | 
|---|
| 1512 |         push(@goners,$child_host); | 
|---|
| 1513 |       } | 
|---|
| 1514 |       else { | 
|---|
| 1515 |         # Host reachable --> Add to collective (duplicates previously culled). | 
|---|
| 1516 |         push(@wc,$child_host); | 
|---|
| 1517 |       } | 
|---|
| 1518 |  | 
|---|
| 1519 |       # Child harvested ==> Decrement cur_fanout | 
|---|
| 1520 |       $cur_fanout--; | 
|---|
| 1521 |  | 
|---|
| 1522 |       # Waitpid for any child.  For "wait some" we will perform a non-blocking | 
|---|
| 1523 |       # child wait, terminating processing if none completed.  For "wait all" | 
|---|
| 1524 |       # we will perform a blocking wait, terminating processing if no children | 
|---|
| 1525 |       # remain. | 
|---|
| 1526 |  | 
|---|
| 1527 |       $child_pid = waitpid(-1, $wait_opt); | 
|---|
| 1528 |       if ((($wait_all eq false) && ($child_pid > 0)) || | 
|---|
| 1529 |           (($wait_all eq true) && ($child_pid != -1))) | 
|---|
| 1530 |       { | 
|---|
| 1531 |         redo PINGWAIT; | 
|---|
| 1532 |       } | 
|---|
| 1533 |     } | 
|---|
| 1534 |   } | 
|---|
| 1535 |  | 
|---|
| 1536 | }  #---------- end of wait_for_kids_and_add_hosts routine -------------- | 
|---|
| 1537 |  | 
|---|
| 1538 |  | 
|---|
| 1539 | #---------------------------------------------------------------------------- | 
|---|
| 1540 | # | 
|---|
| 1541 | # delete_hosts | 
|---|
| 1542 | # | 
|---|
| 1543 | # Called if any hosts don't respond. | 
|---|
| 1544 | # Remove them from the working collective unless the -c flag was set. | 
|---|
| 1545 | # Input is the hostnames to remove from the working collective. | 
|---|
| 1546 | # | 
|---|
| 1547 | #---------------------------------------------------------------------------- | 
|---|
| 1548 |  | 
|---|
| 1549 | sub delete_hosts { | 
|---|
| 1550 |  | 
|---|
| 1551 |   local($child_host,$h,$host_count); | 
|---|
| 1552 |  | 
|---|
| 1553 |   foreach $child_host (@goners) { | 
|---|
| 1554 |     $host_count = 0; | 
|---|
| 1555 |     foreach $h (@wc) { | 
|---|
| 1556 |       if ($h eq $child_host) { | 
|---|
| 1557 |         splice(@wc, $host_count, 1); | 
|---|
| 1558 |       } | 
|---|
| 1559 |       $host_count++; | 
|---|
| 1560 |     } | 
|---|
| 1561 |   } | 
|---|
| 1562 |  | 
|---|
| 1563 | }  #---------- end of delete_hosts routine ----------------------------- | 
|---|
| 1564 |  | 
|---|
| 1565 |  | 
|---|
| 1566 | #---------------------------------------------------------------------------- | 
|---|
| 1567 | # | 
|---|
| 1568 | # infanticide | 
|---|
| 1569 | # | 
|---|
| 1570 | # User has signaled the mmdsh parent - propagate TERM, INT, or QUIT to children. | 
|---|
| 1571 | # (Note - TERM, INT, and QUIT will be propagated to remote processes by rsh). | 
|---|
| 1572 | # Signal any children with SIGTERM if signal is not one of the above. | 
|---|
| 1573 | # Wait for children to manage output and prevent zombies. | 
|---|
| 1574 | # Signal self after setting default signal-handling for self. | 
|---|
| 1575 | # If still alive, exit. | 
|---|
| 1576 | # Input is the signal type. | 
|---|
| 1577 | # | 
|---|
| 1578 | #---------------------------------------------------------------------------- | 
|---|
| 1579 |  | 
|---|
| 1580 | sub infanticide { | 
|---|
| 1581 |  | 
|---|
| 1582 |   local($sig) = @_; | 
|---|
| 1583 |   local($kid_sig); | 
|---|
| 1584 |   #print STDERR "mmdsh: Caught SIG$sig - terminating the kids\n"; | 
|---|
| 1585 |   &prtMsg(366, $sig); | 
|---|
| 1586 |   if ($sig ne 'QUIT' && $sig ne 'INT' && $sig ne 'TERM') { | 
|---|
| 1587 |     $kid_sig = 'TERM'; | 
|---|
| 1588 |     $SIG{'TERM'} = 'IGNORE'; | 
|---|
| 1589 |   } else { | 
|---|
| 1590 |     $kid_sig = $sig; | 
|---|
| 1591 |   } | 
|---|
| 1592 |   $SIG{$sig} = 'DEFAULT'; | 
|---|
| 1593 |   kill $kid_sig, (values %pid); | 
|---|
| 1594 |   &read_pipes_and_wait(true, @hs); | 
|---|
| 1595 |   kill $sig, $$; | 
|---|
| 1596 |   exit($rcode); | 
|---|
| 1597 |  | 
|---|
| 1598 | }       #---------- end of infanticide routine ---------------------------- | 
|---|
| 1599 |  | 
|---|
| 1600 |  | 
|---|
| 1601 | #---------------------------------------------------------------------------- | 
|---|
| 1602 | # | 
|---|
| 1603 | # check_wc | 
|---|
| 1604 | # | 
|---|
| 1605 | # Check to ensure that there are hosts in our working collective. | 
|---|
| 1606 | # | 
|---|
| 1607 | #---------------------------------------------------------------------------- | 
|---|
| 1608 |  | 
|---|
| 1609 | sub check_wc { | 
|---|
| 1610 |  | 
|---|
| 1611 |   if (!@wc) { | 
|---|
| 1612 |     if ($hostCount == 1) { | 
|---|
| 1613 |       #print STDERR "mmdsh:  Node $targetHost is not available to run the command."; | 
|---|
| 1614 |       &prtMsg(573, $targetHost); | 
|---|
| 1615 |       exit(80);   # MM_HostDown | 
|---|
| 1616 |     } | 
|---|
| 1617 |     else { | 
|---|
| 1618 |       #print STDERR "There are no available nodes on which to run the command." | 
|---|
| 1619 |       &prtMsg(367); | 
|---|
| 1620 |       exit(++$rcode); | 
|---|
| 1621 |     } | 
|---|
| 1622 |   } | 
|---|
| 1623 |  | 
|---|
| 1624 | }     #---------- end of check_wc routine --------------------------------- | 
|---|
| 1625 |  | 
|---|
| 1626 |  | 
|---|
| 1627 | #---------------------------------------------------------------------------- | 
|---|
| 1628 | # | 
|---|
| 1629 | # Mainline program | 
|---|
| 1630 | # | 
|---|
| 1631 | # The program continues while there are commands to distribute to the working | 
|---|
| 1632 | # collective via rsh.  Children are forked for each host, up to the fanout | 
|---|
| 1633 | # limit.  Stdout and stderr are piped back from the children to the parent | 
|---|
| 1634 | # who will display the results of the execed rsh's to the parent's stdout | 
|---|
| 1635 | # and stderr. | 
|---|
| 1636 | # | 
|---|
| 1637 | #---------------------------------------------------------------------------- | 
|---|
| 1638 |  | 
|---|
| 1639 | # Determine the execution environment and initialize variables. | 
|---|
| 1640 | chop($osName=`/bin/uname -s`); | 
|---|
| 1641 | if ($osName eq "AIX") { | 
|---|
| 1642 |    $grep="/usr/bin/grep"; | 
|---|
| 1643 |    $ping="/usr/sbin/ping"; | 
|---|
| 1644 |    $DSPMSG="/usr/bin/dspmsg -s 32 mmfs.cat"; | 
|---|
| 1645 | } | 
|---|
| 1646 | elsif ($osName eq "Linux") { | 
|---|
| 1647 |    $grep="/bin/grep"; | 
|---|
| 1648 |    $ping="/bin/ping"; | 
|---|
| 1649 | } | 
|---|
| 1650 | else { | 
|---|
| 1651 |    print STDERR  "mmdsh:  Unknown execution environment $osName\n"; | 
|---|
| 1652 |    exit(-1); | 
|---|
| 1653 | } | 
|---|
| 1654 | $pingTimeout  = 2;       # initial single ping timeout period | 
|---|
| 1655 | $maxPingCount = 3;       # number of pings before declaring a node dead | 
|---|
| 1656 | $fanout_default = 64;    # default fanout value | 
|---|
| 1657 |  | 
|---|
| 1658 | # Flush output filesystem buffers after each write. | 
|---|
| 1659 | select(STDOUT); $| = 1; | 
|---|
| 1660 | select(STDERR); $| = 1; | 
|---|
| 1661 |  | 
|---|
| 1662 | # Get the set environment locales. | 
|---|
| 1663 | use locale; | 
|---|
| 1664 | $lang=$ENV{'LANG'}; | 
|---|
| 1665 | $lcall=$ENV{'LC_ALL'}; | 
|---|
| 1666 | $lccol=$ENV{'LC_COLLATE'}; | 
|---|
| 1667 | $lctyp=$ENV{'LC_TYPE'}; | 
|---|
| 1668 | $lcmon=$ENV{'LC_MONETARY'}; | 
|---|
| 1669 | $lcnum=$ENV{'LC_NUMERIC'}; | 
|---|
| 1670 | $lctim=$ENV{'LC_TIME'}; | 
|---|
| 1671 | $lcmsg=$ENV{'LC_MESSAGES'}; | 
|---|
| 1672 |  | 
|---|
| 1673 | $mmmode=$ENV{'MMMODE'}; | 
|---|
| 1674 | $environmentType=$ENV{'environmentType'}; | 
|---|
| 1675 | $rshPath=$ENV{'GPFS_rshPath'}; | 
|---|
| 1676 | $rcpPath=$ENV{'GPFS_rcpPath'}; | 
|---|
| 1677 | $mmTrace=$ENV{'mmScriptTrace'}; | 
|---|
| 1678 |  | 
|---|
| 1679 | if ($rshPath eq "" || $rshPath eq "_DEFAULT_") { | 
|---|
| 1680 |    $rshPath="/usr/bin/rsh"; | 
|---|
| 1681 | } | 
|---|
| 1682 | elsif ( ! -x $rshPath) { | 
|---|
| 1683 | #esjlrm - fix the above to strip any options | 
|---|
| 1684 |    #die "mmdsh: Invalid or missing remote shell command: $rshPath\n"; | 
|---|
| 1685 |    &prtMsg(422, $rshPath); | 
|---|
| 1686 |    exit(-1); | 
|---|
| 1687 | } | 
|---|
| 1688 |  | 
|---|
| 1689 | if ($rcpPath eq "" || $rcpPath eq "_DEFAULT_") { | 
|---|
| 1690 |    $rcpPath="/usr/bin/rcp"; | 
|---|
| 1691 | } | 
|---|
| 1692 | elsif ( ! -x $rcpPath) { | 
|---|
| 1693 | #esjlrm - fix the above to strip any options | 
|---|
| 1694 |    #die "mmdsh: Invalid or missing remote file copy command: $rcpPath\n"; | 
|---|
| 1695 |    &prtMsg(423, $rcpPath); | 
|---|
| 1696 |    exit(-1); | 
|---|
| 1697 | } | 
|---|
| 1698 |  | 
|---|
| 1699 | $exportcmd = "export LANG=$lang; export LC_ALL=$lcall;  export LC_COLLATE=$lccol; export LC_TYPE=$lctyp; export LC_MONETARY=$lcmon; export LC_NUMERIC=$lcnum; export LC_TIME=$lctim; export LC_MESSAGES=$lcmsg; export MMMODE=$mmmode; export environmentType=$environmentType;  export GPFS_rshPath=$rshPath; export GPFS_rcpPath=$rcpPath; export mmScriptTrace=$mmTrace; "; | 
|---|
| 1700 |  | 
|---|
| 1701 |  | 
|---|
| 1702 | # Set signal handling for forked (child) processes, | 
|---|
| 1703 | #  parse the command line, and determine our working collective. | 
|---|
| 1704 | &set_signals; | 
|---|
| 1705 | &parse; | 
|---|
| 1706 | &get_wc; | 
|---|
| 1707 | &display_wc; | 
|---|
| 1708 | &set_defaults; | 
|---|
| 1709 | &check_wc; | 
|---|
| 1710 |  | 
|---|
| 1711 | # Perform each command on the nodes in our working collective. | 
|---|
| 1712 | while ($command = &get_command) { | 
|---|
| 1713 |  | 
|---|
| 1714 |    if ($iflag) { | 
|---|
| 1715 |      print STDERR "mmdsh: Command to run: $command\n\n"; | 
|---|
| 1716 |    } | 
|---|
| 1717 |  | 
|---|
| 1718 |    # If the special command _SELECT_FROM_FILE_ is specified, | 
|---|
| 1719 |    # the command to be executed by each of the nodes is given | 
|---|
| 1720 |    # in the file specified in the mmdshCommandsFile variable. | 
|---|
| 1721 |    if ($command eq "_SELECT_FROM_FILE_") { | 
|---|
| 1722 |      $selectCommandFromFile++; | 
|---|
| 1723 |      unless ($mmdshCommandsFile = $ENV{'mmdshCommandsFile'}) { | 
|---|
| 1724 |        die "mmdsh: mmdshCommandsFile environment variable not set\n"; | 
|---|
| 1725 |      } | 
|---|
| 1726 |      unless ( -f $mmdshCommandsFile ) { | 
|---|
| 1727 |        #die "mmdsh: File $mmdshCommandsFile not found\n"; | 
|---|
| 1728 |        &prtMsg(364, $mmdshCommandsFile, "\'$!\'"); | 
|---|
| 1729 |        exit(-1); | 
|---|
| 1730 |      } | 
|---|
| 1731 |    } | 
|---|
| 1732 |  | 
|---|
| 1733 |    # Clear out the host array and pid hash (also used in host verification) | 
|---|
| 1734 |    undef @hs; | 
|---|
| 1735 |    undef %pid; | 
|---|
| 1736 |  | 
|---|
| 1737 |    # The working collective, @wc, at this point is guaranteed to contain only | 
|---|
| 1738 |    # unique entries.  This prevents key collisions on the %pid hash table. | 
|---|
| 1739 |    foreach $host (@wc) { | 
|---|
| 1740 |  | 
|---|
| 1741 |       # If the special command _SELECT_FROM_FILE_ is specified, | 
|---|
| 1742 |       # retrieve the command string to be executed by the node. | 
|---|
| 1743 |  | 
|---|
| 1744 |       if ($selectCommandFromFile) { | 
|---|
| 1745 |         $command = `$grep -w ^$host $mmdshCommandsFile`; | 
|---|
| 1746 |         chop($command); | 
|---|
| 1747 |  | 
|---|
| 1748 |         # If there is no command for this host, move on. | 
|---|
| 1749 |         unless ($command) { | 
|---|
| 1750 |           if ($iflag) { | 
|---|
| 1751 |             print STDERR "mmdsh: $host: No command found.\n"; | 
|---|
| 1752 |           } | 
|---|
| 1753 |           next; | 
|---|
| 1754 |         } | 
|---|
| 1755 |  | 
|---|
| 1756 |         # Remove the hostname from the command string. | 
|---|
| 1757 |         @dsh_ARGV = split(' ',$command); | 
|---|
| 1758 |         shift(@dsh_ARGV); | 
|---|
| 1759 |         $command = join(' ',@dsh_ARGV); | 
|---|
| 1760 |  | 
|---|
| 1761 |         if ($iflag) { | 
|---|
| 1762 |           print STDERR "mmdsh: $host: $command \n"; | 
|---|
| 1763 |         } | 
|---|
| 1764 |       } | 
|---|
| 1765 |  | 
|---|
| 1766 |  | 
|---|
| 1767 |       # Create filehandles for pipe ends. | 
|---|
| 1768 |       $r_out{$host} = "READ_STDOUT_" . $host; | 
|---|
| 1769 |       $w_out{$host} = "WRITE_STDOUT_" . $host; | 
|---|
| 1770 |       $r_err{$host} = "READ_STDERR_" . $host; | 
|---|
| 1771 |       $w_err{$host} = "WRITE_STDERR_" . $host; | 
|---|
| 1772 |  | 
|---|
| 1773 |       # Open pipes for this host's stdout and stderr from rsh. | 
|---|
| 1774 |       if (pipe($r_out{$host}, $w_out{$host}) < 0) { | 
|---|
| 1775 |          #die "mmdsh: Couldn't pipe: $!\n"; | 
|---|
| 1776 |          &prtMsg(368, "\'$!\'"); | 
|---|
| 1777 |          exit(-1); | 
|---|
| 1778 |       } | 
|---|
| 1779 |       if (pipe($r_err{$host}, $w_err{$host}) < 0) { | 
|---|
| 1780 |          #die "mmdsh: Couldn't pipe: $!\n"; | 
|---|
| 1781 |          &prtMsg(368, "\'$!\'"); | 
|---|
| 1782 |          exit(-1); | 
|---|
| 1783 |       } | 
|---|
| 1784 |  | 
|---|
| 1785 |       # Fork a child to exec the rsh. | 
|---|
| 1786 |       MAINFORK: { | 
|---|
| 1787 |  | 
|---|
| 1788 |          if ($pid{$host} = fork) { | 
|---|
| 1789 |  | 
|---|
| 1790 |             # Parent code - | 
|---|
| 1791 |             # Close unneeded ends of pipes. | 
|---|
| 1792 |             # Parent will wait for child processes if fanout limit reached. | 
|---|
| 1793 |             close($w_out{$host}); | 
|---|
| 1794 |             close($w_err{$host}); | 
|---|
| 1795 |  | 
|---|
| 1796 |             push(@hs,$host); | 
|---|
| 1797 |  | 
|---|
| 1798 |             if (++$cur_fanout >= $fanout) { | 
|---|
| 1799 |                &read_pipes_and_wait(false, @hs); | 
|---|
| 1800 |             } | 
|---|
| 1801 |  | 
|---|
| 1802 |          } elsif (defined $pid{$host}) { | 
|---|
| 1803 |  | 
|---|
| 1804 |             # Child code - | 
|---|
| 1805 |             # Close unneeded ends of pipes. | 
|---|
| 1806 |             # Redirect stdout and stderr to output pipes. | 
|---|
| 1807 |             # Exec rsh. | 
|---|
| 1808 |             # stdout/stderr will go to pipes to be read by parent. | 
|---|
| 1809 |             close($r_out{$host}); | 
|---|
| 1810 |             close($r_err{$host}); | 
|---|
| 1811 |  | 
|---|
| 1812 |             unless (open(STDOUT, ">&$w_out{$host}")) { | 
|---|
| 1813 |                #die "mmdsh: Cannot redirect STDOUT: $!\n"; | 
|---|
| 1814 |                &prtMsg(369, 'STDOUT', "\'$!\'"); | 
|---|
| 1815 |                exit(-1); | 
|---|
| 1816 |             } | 
|---|
| 1817 |             unless (open(STDERR, ">&$w_err{$host}")) { | 
|---|
| 1818 |                #die "mmdsh: Cannot redirect STDERR: $!\n"; | 
|---|
| 1819 |                &prtMsg(369, 'STDERR', "\'$!\'"); | 
|---|
| 1820 |                exit(-1); | 
|---|
| 1821 |             } | 
|---|
| 1822 |  | 
|---|
| 1823 |             select(STDOUT); $| = 1; | 
|---|
| 1824 |             select(STDERR); $| = 1; | 
|---|
| 1825 |  | 
|---|
| 1826 |             # If the -I option is specified, copy the specified files | 
|---|
| 1827 |             # to the remote host prior to invoking the actual command. | 
|---|
| 1828 |             if ($stageFile) { | 
|---|
| 1829 |               $rcpCommandString = "$rcpPath -p $fileToCopy $host:$fileToCopy"; | 
|---|
| 1830 |               if ($iflag) { | 
|---|
| 1831 |                 print STDERR "mmdsh: $rcpCommandString \n"; | 
|---|
| 1832 |               } | 
|---|
| 1833 |               $rcpOutput = `LC_ALL=C $rcpCommandString 2>&1`; | 
|---|
| 1834 |               $rcpRc = $? >> 8; | 
|---|
| 1835 |  | 
|---|
| 1836 |               # If the rcopy fails, move to the next host. | 
|---|
| 1837 |               if ($rcpRc > 0 && $rcpOutput !~ /refer to the same file/) { | 
|---|
| 1838 |                 if ($rcpOutput) { | 
|---|
| 1839 |                   printf STDERR "%s", $rcpOutput; | 
|---|
| 1840 |                 } | 
|---|
| 1841 |                 &prtMsg(171, $rcpCommandString, $rcpRc); | 
|---|
| 1842 |                 die "mmdsh: $command will not be executed on $host.\n"; | 
|---|
| 1843 |               } | 
|---|
| 1844 |             } | 
|---|
| 1845 |  | 
|---|
| 1846 |             if ($stageFile2) { | 
|---|
| 1847 |               $rcpCommandString = "$rcpPath -p $fileToCopy2 $host:$fileToCopy2"; | 
|---|
| 1848 |               if ($iflag) { | 
|---|
| 1849 |                 print STDERR "mmdsh: $rcpCommandString \n"; | 
|---|
| 1850 |               } | 
|---|
| 1851 |               $rcpOutput = `LC_ALL=C $rcpCommandString 2>&1`; | 
|---|
| 1852 |               $rcpRc = $? >> 8; | 
|---|
| 1853 |  | 
|---|
| 1854 |               # If the rcopy fails, move to the next host. | 
|---|
| 1855 |               if ($rcpRc > 0 && $rcpOutput !~ /refer to the same file/) { | 
|---|
| 1856 |                 if ($rcpOutput) { | 
|---|
| 1857 |                   printf STDERR "%s", $rcpOutput; | 
|---|
| 1858 |                 } | 
|---|
| 1859 |                 &prtMsg(171, $rcpCommandString, $rcpRc); | 
|---|
| 1860 |                 die "mmdsh: $command will not be executed on $host.\n"; | 
|---|
| 1861 |               } | 
|---|
| 1862 |             } | 
|---|
| 1863 |  | 
|---|
| 1864 |             # Execute the command on the remote host. | 
|---|
| 1865 |             if (!@dsh_ARGV) { | 
|---|
| 1866 |                # mmdsh was invoked without specifying a command. | 
|---|
| 1867 |                # The command to execute comes from the mmdsh prompt. | 
|---|
| 1868 |          if ($ENV{'DSHPATH'}) { | 
|---|
| 1869 |                   exec ($rshPath, | 
|---|
| 1870 |                         $host, '-n', '-l', $login, | 
|---|
| 1871 |                         "export PATH=$ENV{'DSHPATH'};", | 
|---|
| 1872 |                         $exportcmd, $command)                 || | 
|---|
| 1873 |                   die "mmdsh: rsh: $host $command: $!\n"; | 
|---|
| 1874 |          } else { | 
|---|
| 1875 |                   exec ($rshPath, | 
|---|
| 1876 |                         $host, '-n', '-l', $login, | 
|---|
| 1877 |                         $exportcmd, $command)                 || | 
|---|
| 1878 |                   die "mmdsh: rsh: $host $command: $!\n"; | 
|---|
| 1879 |                } | 
|---|
| 1880 |             } else { | 
|---|
| 1881 |                # The command to execute comes from the mmdsh command line. | 
|---|
| 1882 |                # This is the path taken by the mm commands. | 
|---|
| 1883 |          if ($ENV{'DSHPATH'}) { | 
|---|
| 1884 |                   exec ($rshPath, | 
|---|
| 1885 |                         $host, '-n', '-l', $login, | 
|---|
| 1886 |                         "export PATH=$ENV{'DSHPATH'};", | 
|---|
| 1887 |                         $exportcmd, @dsh_ARGV)                || | 
|---|
| 1888 |                   die "mmdsh: rsh: $host @dsh_ARGV: $!\n"; | 
|---|
| 1889 |          } else { | 
|---|
| 1890 |                   exec ($rshPath, | 
|---|
| 1891 |                         $host, '-n', '-l', $login, | 
|---|
| 1892 |                         $exportcmd, @dsh_ARGV)                || | 
|---|
| 1893 |                   die "mmdsh: rsh: $host @dsh_ARGV: $!\n"; | 
|---|
| 1894 |                } | 
|---|
| 1895 |       } | 
|---|
| 1896 |  | 
|---|
| 1897 |          } else { | 
|---|
| 1898 |  | 
|---|
| 1899 |            # Try again.  The fork must have failed due to a resource problem. | 
|---|
| 1900 |            if ($iflag) { | 
|---|
| 1901 |              print STDERR "mmdsh: fork() failed; will retry in 5 seconds.\n"; | 
|---|
| 1902 |            } | 
|---|
| 1903 |            sleep 5; | 
|---|
| 1904 |            redo MAINFORK; | 
|---|
| 1905 |          } | 
|---|
| 1906 |       } | 
|---|
| 1907 |    } | 
|---|
| 1908 |  | 
|---|
| 1909 |    # Parent continues here after forking all the children for this command. | 
|---|
| 1910 |    # Get the results of any remaining rsh's (the number of hosts in our | 
|---|
| 1911 |    #  working collective may not be a multiple of the fanout value). | 
|---|
| 1912 |    # Get rid of any hosts that have failed. | 
|---|
| 1913 |    # Display the working collective and command. | 
|---|
| 1914 |    &read_pipes_and_wait(true, @hs); | 
|---|
| 1915 |    &delete_hosts; | 
|---|
| 1916 |    unless ($done) { | 
|---|
| 1917 |       $cur_fanout = 0; | 
|---|
| 1918 |       &check_wc; | 
|---|
| 1919 |       &display_wc; | 
|---|
| 1920 |    } | 
|---|
| 1921 | } | 
|---|
| 1922 |  | 
|---|
| 1923 | # If requested, delete the -I files. | 
|---|
| 1924 | if ($stageFile && $kflag) { | 
|---|
| 1925 |   `/bin/rm -f $fileToCopy $fileToCopy2 >/dev/null 2>&1`; | 
|---|
| 1926 | } | 
|---|
| 1927 |  | 
|---|
| 1928 | # exit | 
|---|
| 1929 |  | 
|---|
| 1930 | exit($rcode);       #---------- end of mainline program ---------------- | 
|---|
| 1931 |  | 
|---|