halt.c revision f040a7a67fcbe6fabda79a643f3fd1a520472325
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Common code for halt(1M), poweroff(1M), and reboot(1M). We use
* argv[0] to determine which behavior to exhibit.
*/
#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <libscf.h>
#include <locale.h>
#include <libintl.h>
#include <syslog.h>
#include <signal.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <time.h>
#include <utmpx.h>
#include <pwd.h>
#include <zone.h>
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
extern int audit_halt_setup(int, char **);
extern int audit_halt_success(void);
extern int audit_halt_fail(void);
extern int audit_reboot_setup(void);
extern int audit_reboot_success(void);
extern int audit_reboot_fail(void);
typedef struct ctidlist_struct {
struct ctidlist_struct *next;
} ctidlist_t;
#define FMRI_STARTD_CONTRACT \
#define ZONEADM_PROG "/usr/sbin/zoneadm"
static void
{
scf_handle_t *h;
int ret;
h = scf_handle_create(SCF_VERSION);
if (h == NULL)
return;
ret = scf_handle_bind(h);
if (ret) {
return;
}
prop = scf_property_create(h);
val = scf_value_create(h);
goto out;
if (ret)
goto out;
if (ret)
goto out;
if (ret)
goto out;
if (ret)
goto out;
out:
if (prop)
if (val)
(void) scf_handle_unbind(h);
}
static void
{
if (startdct != -1)
}
#define FMRI_RESTARTER_PROP "/:properties/general/restarter"
#define FMRI_CONTRACT_PROP "/:properties/restarter/contract"
static int
{
return (-1);
return (-1);
return (0);
}
static void
{
scf_handle_t *h;
char *fmri;
int ret;
if (length <= 0)
return;
length++;
h = scf_handle_create(SCF_VERSION);
if (!h)
return;
ret = scf_handle_bind(h);
if (ret) {
return;
}
sc = scf_scope_create(h);
svc = scf_service_create(h);
inst = scf_instance_create(h);
snap = scf_snapshot_create(h);
pg = scf_pg_create(h);
prop = scf_property_create(h);
val = scf_value_create(h);
siter = scf_iter_create(h);
iiter = scf_iter_create(h);
goto out;
if (ret)
goto out;
if (ret)
goto out;
if (ret)
continue;
if (ret)
else
SCF_PG_GENERAL, pg);
if (ret)
continue;
if (ret)
continue;
if (ret)
continue;
if (ret)
continue;
continue;
continue;
if (ret)
continue;
if (ret)
continue;
if (ret)
continue;
if (ret)
continue;
}
}
}
out:
if (sc)
if (svc)
if (inst)
if (snap)
if (pg)
if (prop)
if (val)
if (siter)
if (iiter)
(void) scf_handle_unbind(h);
}
static void
{
}
static void
{
stop_startd();
}
static void
{
}
/*
* Copy an array of strings into buf, separated by spaces. Returns 0 on
* success.
*/
static int
{
return (-1);
return (-1);
return (-1);
}
return (0);
}
/*
* Halt every zone on the system. We are committed to doing a shutdown
* even if something goes wrong here. If something goes wrong, we just
* continue with the shutdown. Return non-zero if we need to wait for zones to
* halt later on.
*/
static int
halt_zones(const char *name)
{
int i;
char zname[ZONENAME_MAX];
/*
* Get a list of zones. If the number of zones changes in between the
* two zone_list calls, try again.
*/
for (;;) {
if (nz == 1)
return (0);
gettext("%s: Could not halt zones"
" (out of memory).\n"), name);
return (0);
}
break;
}
if (nz == 2) {
gettext("%s: Halting 1 zone.\n"),
name);
} else {
gettext("%s: Halting %i zones.\n"),
}
for (i = 0; i < nz; i++) {
if (zones[i] == GLOBAL_ZONEID)
continue;
/*
* getzonenamebyid should only fail if we raced with
* another process trying to shut down the zone.
* We assume this happened and ignore the error.
*/
gettext("%s: Unexpected error while "
"looking up zone %ul: %s.\n"),
}
continue;
}
if (pid < 0) {
gettext("%s: Zone \"%s\" could not be"
" halted (could not fork(): %s).\n"),
continue;
}
if (pid == 0) {
gettext("%s: Zone \"%s\" could not be halted"
exit(0);
}
}
return (1);
}
/*
* This function tries to wait for all non-global zones to go away.
* It will timeout if no progress is made for 5 seconds, or a total of
* 30 seconds elapses.
*/
static void
check_zones_haltedness(const char *name)
{
int t = 0, t_prog = 0;
do {
if (nz == 1)
return;
(void) sleep(1);
t_prog = 0;
t++;
t_prog++;
if (t == 10) {
if (nz == 2) {
gettext("%s: Still waiting for 1 zone to "
"halt. Will wait up to 20 seconds.\n"),
name);
} else {
gettext("%s: Still waiting for %i zones "
"to halt. Will wait up to 20 seconds.\n"),
}
}
}
int
{
const char *usage;
int need_check_zones;
(void) textdomain(TEXT_DOMAIN);
cmd = A_SHUTDOWN;
cmd = A_SHUTDOWN;
fcn = AD_POWEROFF;
(void) audit_reboot_setup();
cmd = A_SHUTDOWN;
} else {
return (1);
}
switch (c) {
case 'd':
if (zoneid == GLOBAL_ZONEID)
else {
gettext("%s: -d only valid from global"
" zone\n"), cmdname);
return (1);
}
break;
case 'l':
needlog = 0;
break;
case 'n':
nosync = 1;
break;
case 'q':
qflag = 1;
break;
case 'y':
break;
default:
/*
* TRANSLATION_NOTE
* Don't translate the words "halt" or "reboot"
*/
return (1);
}
}
if (argc != 0) {
return (1);
}
/* Gather the arguments into bootargs_buf. */
0) {
return (1);
}
}
if (geteuid() != 0) {
goto fail;
}
/*
* TRANSLATION_NOTE
* Don't translate ``halt -y''
*/
goto fail;
}
if (needlog) {
char *tty;
user = "root";
else
}
/*
* We must assume success and log it before auditd is terminated.
*/
aval = audit_reboot_success();
else
aval = audit_halt_success();
if (aval == -1) {
if (needlog)
}
init_pid = -1;
}
/*
* We start to fork a bunch of zoneadms to halt any active zones.
* This will proceed with halt in parallel until we call
* check_zone_haltedness later on.
*/
}
/* sync boot archive in the global zone */
}
/*
* If we're not forcing a crash dump, mark the system as quiescing for
* smf(5)'s benefit, and idle the init process.
*/
/*
* TRANSLATION_NOTE
* Don't translate the word "init"
*/
goto fail;
}
gettext("%s: could not create %s.\n"),
/*
* Stop all restarters so they do not try to restart services
* that are terminated.
*/
/*
* Wait a little while for zones to shutdown.
*/
if (need_check_zones) {
gettext("%s: Completing system halt.\n"),
cmdname);
}
}
/*
* Make sure we don't get stopped by a jobcontrol shell
* once we start killing everybody.
*/
/*
* If we're not forcing a crash dump, give everyone 5 seconds to
* handle a SIGTERM and clean up properly.
*/
(void) sleep(5);
}
else
sync();
}
do
if (init_pid != -1)
/* tell init to restate current level */
fail:
(void) audit_reboot_fail();
else
(void) audit_halt_fail();
return (1);
}