Print this page
6805730 some simple changes would make 'init 5' much faster
6809492 startd shouldn't let hung subprocesses impede shutdown


   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * fork.c - safe forking for svc.startd
  28  *
  29  * fork_configd() and fork_sulogin() are related, special cases that handle the
  30  * spawning of specific client processes for svc.startd.
  31  */
  32 
  33 #include <sys/contract/process.h>
  34 #include <sys/corectl.h>
  35 #include <sys/ctfs.h>
  36 #include <sys/stat.h>
  37 #include <sys/types.h>
  38 #include <sys/uio.h>
  39 #include <sys/wait.h>
  40 #include <assert.h>
  41 #include <errno.h>
  42 #include <fcntl.h>
  43 #include <libcontract.h>
  44 #include <libcontract_priv.h>
  45 #include <libscf_priv.h>
  46 #include <limits.h>

  47 #include <port.h>
  48 #include <signal.h>
  49 #include <stdarg.h>
  50 #include <stdio.h>
  51 #include <stdlib.h>
  52 #include <string.h>
  53 #include <unistd.h>
  54 #include <utmpx.h>

  55 
  56 #include "configd_exit.h"
  57 #include "protocol.h"
  58 #include "startd.h"
  59 
  60 static  struct  utmpx   *utmpp; /* pointer for getutxent() */
  61 
  62 pid_t
  63 startd_fork1(int *forkerr)
  64 {
  65         pid_t p;
  66 
  67         /*
  68          * prefork stack
  69          */
  70         wait_prefork();
  71 
  72         p = fork1();
  73 
  74         if (p == -1 && forkerr != NULL)


 661         setlog(log);
 662 
 663         now = time(NULL);
 664         sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
 665             localtime_r(&now, &ltime));
 666         assert(sz != 0);
 667 
 668         (void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
 669 
 670         if (rl == 'S')
 671                 pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
 672         else
 673                 pathenv = "PATH=/usr/sbin:/usr/bin";
 674 
 675         nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
 676 
 677         (void) execle(path, path, arg, 0, nenv);
 678 
 679         perror("exec");
 680         exit(0);











































































































 681 }


   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * fork.c - safe forking for svc.startd
  28  *
  29  * fork_configd() and fork_sulogin() are related, special cases that handle the
  30  * spawning of specific client processes for svc.startd.
  31  */
  32 
  33 #include <sys/contract/process.h>
  34 #include <sys/corectl.h>
  35 #include <sys/ctfs.h>
  36 #include <sys/stat.h>
  37 #include <sys/types.h>
  38 #include <sys/uio.h>
  39 #include <sys/wait.h>
  40 #include <assert.h>
  41 #include <errno.h>
  42 #include <fcntl.h>
  43 #include <libcontract.h>
  44 #include <libcontract_priv.h>
  45 #include <libscf_priv.h>
  46 #include <limits.h>
  47 #include <poll.h>
  48 #include <port.h>
  49 #include <signal.h>
  50 #include <stdarg.h>
  51 #include <stdio.h>
  52 #include <stdlib.h>
  53 #include <string.h>
  54 #include <unistd.h>
  55 #include <utmpx.h>
  56 #include <spawn.h>
  57 
  58 #include "configd_exit.h"
  59 #include "protocol.h"
  60 #include "startd.h"
  61 
  62 static  struct  utmpx   *utmpp; /* pointer for getutxent() */
  63 
  64 pid_t
  65 startd_fork1(int *forkerr)
  66 {
  67         pid_t p;
  68 
  69         /*
  70          * prefork stack
  71          */
  72         wait_prefork();
  73 
  74         p = fork1();
  75 
  76         if (p == -1 && forkerr != NULL)


 663         setlog(log);
 664 
 665         now = time(NULL);
 666         sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
 667             localtime_r(&now, &ltime));
 668         assert(sz != 0);
 669 
 670         (void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
 671 
 672         if (rl == 'S')
 673                 pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
 674         else
 675                 pathenv = "PATH=/usr/sbin:/usr/bin";
 676 
 677         nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
 678 
 679         (void) execle(path, path, arg, 0, nenv);
 680 
 681         perror("exec");
 682         exit(0);
 683 }
 684 
 685 extern char **environ;
 686 
 687 /*
 688  * A local variation on system(3c) which accepts a timeout argument.  This
 689  * allows us to better ensure that the system will actually shut down.
 690  *
 691  * gracetime specifies an amount of time in seconds which the routine must wait
 692  * after the command exits, to allow for asynchronous effects (like sent
 693  * signals) to take effect.  This can be zero.
 694  */
 695 void
 696 fork_with_timeout(const char *cmd, uint_t gracetime, uint_t timeout)
 697 {
 698         int err = 0;
 699         pid_t pid;
 700         char *argv[4];
 701         posix_spawnattr_t attr;
 702         posix_spawn_file_actions_t factions;
 703 
 704         sigset_t mask, savemask;
 705         uint_t msec_timeout;
 706         uint_t msec_spent = 0;
 707         uint_t msec_gracetime;
 708         int status;
 709 
 710         msec_timeout = timeout * 1000;
 711         msec_gracetime = gracetime * 1000;
 712 
 713         /*
 714          * See also system(3c) in libc.  This is very similar, except
 715          * that we avoid some unneeded complexity.
 716          */
 717         err = posix_spawnattr_init(&attr);
 718         if (err == 0)
 719                 err = posix_spawnattr_setflags(&attr,
 720                     POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
 721                     POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP |
 722                     POSIX_SPAWN_NOEXECERR_NP);
 723 
 724         /*
 725          * We choose to close fd's above 2, a deviation from system.
 726          */
 727         if (err == 0)
 728                 err = posix_spawn_file_actions_init(&factions);
 729         if (err == 0)
 730                 err = posix_spawn_file_actions_addclosefrom_np(&factions,
 731                     STDERR_FILENO + 1);
 732 
 733         (void) sigemptyset(&mask);
 734         (void) sigaddset(&mask, SIGCHLD);
 735         (void) thr_sigsetmask(SIG_BLOCK, &mask, &savemask);
 736 
 737         argv[0] = "/bin/sh";
 738         argv[1] = "-c";
 739         argv[2] = (char *)cmd;
 740         argv[3] = NULL;
 741 
 742         if (err == 0)
 743                 err = posix_spawn(&pid, "/bin/sh", &factions, &attr,
 744                     (char *const *)argv, (char *const *)environ);
 745 
 746         (void) posix_spawnattr_destroy(&attr);
 747         (void) posix_spawn_file_actions_destroy(&factions);
 748 
 749         if (err) {
 750                 uu_warn("Failed to spawn %s: %s\n", cmd, strerror(err));
 751         } else {
 752                 for (;;) {
 753                         int w;
 754                         w = waitpid(pid, &status, WNOHANG);
 755                         if (w == -1 && errno != EINTR)
 756                                 break;
 757                         if (w > 0) {
 758                                 /*
 759                                  * Command succeeded, so give it gracetime
 760                                  * seconds for it to have an effect.
 761                                  */
 762                                 if (status == 0 && msec_gracetime != 0)
 763                                         (void) poll(NULL, 0, msec_gracetime);
 764                                 break;
 765                         }
 766 
 767                         (void) poll(NULL, 0, 100);
 768                         msec_spent += 100;
 769                         /*
 770                          * If we timed out, kill off the process, then try to
 771                          * wait for it-- it's possible that we could accumulate
 772                          * a zombie here since we don't allow waitpid to hang,
 773                          * but it's better to let that happen and continue to
 774                          * make progress.
 775                          */
 776                         if (msec_spent >= msec_timeout) {
 777                                 uu_warn("'%s' timed out after %d "
 778                                     "seconds.  Killing.\n", cmd,
 779                                     timeout);
 780                                 (void) kill(pid, SIGTERM);
 781                                 (void) poll(NULL, 0, 100);
 782                                 (void) kill(pid, SIGKILL);
 783                                 (void) poll(NULL, 0, 100);
 784                                 (void) waitpid(pid, &status, WNOHANG);
 785                                 break;
 786                         }
 787                 }
 788         }
 789         (void) thr_sigsetmask(SIG_BLOCK, &savemask, NULL);
 790 }