2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A
2N/A/*
2N/A * Wrapper function to implement reboot w/ arguments on x86
2N/A * platforms. Extract reboot arguments and place them in
2N/A * in a transient entry in /[stub]boot/grub/menu.lst
2N/A * All other commands are passed through.
2N/A */
2N/A
2N/A#include "lint.h"
2N/A#include "mtlib.h"
2N/A#include <fcntl.h>
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/uadmin.h>
2N/A#include <unistd.h>
2N/A#include <strings.h>
2N/A#include <pthread.h>
2N/A#include <zone.h>
2N/A#include <libscf.h>
2N/A#include <thread.h>
2N/A#include <dlfcn.h>
2N/A#include <atomic.h>
2N/A
2N/A/*
2N/A * Pull in the following three interfaces from libscf without introducing
2N/A * a dependency on it, which since libscf depends on libc would be circular:
2N/A *
2N/A * scf_simple_prop_get
2N/A * scf_simple_prop_next_boolean
2N/A * scf_simple_prop_free
2N/A */
2N/Atypedef scf_simple_prop_t *(*scf_simple_prop_get_t)(scf_handle_t *,
2N/A const char *, const char *, const char *);
2N/Astatic scf_simple_prop_get_t real_scf_simple_prop_get = NULL;
2N/Atypedef uint8_t *(*scf_simple_prop_next_boolean_t)(scf_simple_prop_t *);
2N/Astatic scf_simple_prop_next_boolean_t real_scf_simple_prop_next_boolean = NULL;
2N/Atypedef void (*scf_simple_prop_free_t)(scf_simple_prop_t *);
2N/Astatic scf_simple_prop_free_t real_scf_simple_prop_free = NULL;
2N/Astatic mutex_t scf_lock = DEFAULTMUTEX;
2N/A
2N/Astatic void
2N/Aload_scf(void)
2N/A{
2N/A void *scf_handle = dlopen("libscf.so.1", RTLD_LAZY);
2N/A scf_simple_prop_get_t scf_simple_prop_get = (scf_handle == NULL)? NULL :
2N/A (scf_simple_prop_get_t)dlsym(scf_handle, "scf_simple_prop_get");
2N/A scf_simple_prop_next_boolean_t scf_simple_prop_next_boolean =
2N/A (scf_handle == NULL)? NULL :
2N/A (scf_simple_prop_next_boolean_t)dlsym(scf_handle,
2N/A "scf_simple_prop_next_boolean");
2N/A scf_simple_prop_free_t scf_simple_prop_free =
2N/A (scf_handle == NULL)? NULL :
2N/A (scf_simple_prop_free_t)dlsym(scf_handle, "scf_simple_prop_free");
2N/A
2N/A lmutex_lock(&scf_lock);
2N/A if (real_scf_simple_prop_get == NULL ||
2N/A real_scf_simple_prop_next_boolean == NULL ||
2N/A real_scf_simple_prop_free == NULL) {
2N/A if (scf_simple_prop_get == NULL)
2N/A real_scf_simple_prop_get = (scf_simple_prop_get_t)(-1);
2N/A else {
2N/A real_scf_simple_prop_get = scf_simple_prop_get;
2N/A scf_handle = NULL; /* don't dlclose it */
2N/A }
2N/A if (scf_simple_prop_next_boolean == NULL)
2N/A real_scf_simple_prop_next_boolean =
2N/A (scf_simple_prop_next_boolean_t)(-1);
2N/A else {
2N/A real_scf_simple_prop_next_boolean =
2N/A scf_simple_prop_next_boolean;
2N/A scf_handle = NULL; /* don't dlclose it */
2N/A }
2N/A if (scf_simple_prop_free == NULL)
2N/A real_scf_simple_prop_free =
2N/A (scf_simple_prop_free_t)(-1);
2N/A else {
2N/A real_scf_simple_prop_free = scf_simple_prop_free;
2N/A scf_handle = NULL; /* don't dlclose it */
2N/A }
2N/A membar_producer();
2N/A }
2N/A lmutex_unlock(&scf_lock);
2N/A
2N/A if (scf_handle)
2N/A (void) dlclose(scf_handle);
2N/A}
2N/A
2N/Astatic void
2N/Acheck_archive_update(void)
2N/A{
2N/A scf_simple_prop_t *prop = NULL;
2N/A boolean_t update_flag = B_FALSE;
2N/A char *fmri = "svc:/system/boot-config:default";
2N/A uint8_t *ret_val = NULL;
2N/A
2N/A if (real_scf_simple_prop_get == NULL ||
2N/A real_scf_simple_prop_next_boolean == NULL ||
2N/A real_scf_simple_prop_free == NULL) {
2N/A load_scf();
2N/A }
2N/A if (real_scf_simple_prop_get == (scf_simple_prop_get_t)(-1) ||
2N/A real_scf_simple_prop_next_boolean ==
2N/A (scf_simple_prop_next_boolean_t)(-1) ||
2N/A real_scf_simple_prop_free == (scf_simple_prop_free_t)(-1)) {
2N/A return;
2N/A }
2N/A
2N/A prop = real_scf_simple_prop_get(NULL, fmri, "config",
2N/A "uadmin_boot_archive_sync");
2N/A if (prop) {
2N/A if ((ret_val = real_scf_simple_prop_next_boolean(prop)) !=
2N/A NULL)
2N/A update_flag = (*ret_val == 0) ? B_FALSE :
2N/A B_TRUE;
2N/A real_scf_simple_prop_free(prop);
2N/A }
2N/A
2N/A if (update_flag == B_TRUE)
2N/A (void) system("/usr/sbin/bootadm update-archive");
2N/A}
2N/Astatic int
2N/Alegal_arg(char *bargs)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < BOOTARGS_MAX; i++, bargs++) {
2N/A if (*bargs == 0 && i > 0)
2N/A return (i);
2N/A if (!isprint(*bargs))
2N/A break;
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/Astatic char quote[] = "\'";
2N/A
2N/Aint
2N/Auadmin(int cmd, int fcn, uintptr_t mdep)
2N/A{
2N/A extern int __uadmin(int cmd, int fcn, uintptr_t mdep);
2N/A char *bargs, cmdbuf[256];
2N/A
2N/A bargs = (char *)mdep;
2N/A
2N/A if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID &&
2N/A (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
2N/A int off = 0;
2N/A
2N/A switch (fcn) {
2N/A case AD_IBOOT:
2N/A case AD_SBOOT:
2N/A case AD_SIBOOT:
2N/A /*
2N/A * These functions fabricate appropriate bootargs.
2N/A * If bootargs are passed in, map these functions
2N/A * to AD_BOOT.
2N/A */
2N/A if (bargs == 0) {
2N/A switch (fcn) {
2N/A case AD_IBOOT:
2N/A bargs = "-a";
2N/A break;
2N/A case AD_SBOOT:
2N/A bargs = "-s";
2N/A break;
2N/A case AD_SIBOOT:
2N/A bargs = "-sa";
2N/A break;
2N/A }
2N/A }
2N/A /*FALLTHROUGH*/
2N/A case AD_BOOT:
2N/A case AD_FASTREBOOT:
2N/A if (bargs == 0)
2N/A break; /* no args */
2N/A if (legal_arg(bargs) < 0)
2N/A break; /* bad args */
2N/A
2N/A /* avoid cancellation in system() */
2N/A (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
2N/A NULL);
2N/A
2N/A if (fcn == AD_FASTREBOOT) {
2N/A char *newarg, *head;
2N/A char bargs_scratch[BOOTARGS_MAX];
2N/A
2N/A bzero(bargs_scratch, BOOTARGS_MAX);
2N/A
2N/A bcopy(bargs, bargs_scratch, strlen(bargs));
2N/A head = bargs_scratch;
2N/A newarg = strtok(bargs_scratch, " ");
2N/A
2N/A if (newarg == NULL || newarg[0] == '-')
2N/A break;
2N/A
2N/A /* First argument is rootdir */
2N/A if (strncmp(&newarg[strlen(newarg)-4],
2N/A "unix", 4) != 0) {
2N/A newarg = strtok(NULL, " ");
2N/A off = newarg - head;
2N/A }
2N/A
2N/A /*
2N/A * If we are using alternate root via
2N/A * mountpoint or a different BE, don't
2N/A * bother to update the temp menu entry.
2N/A */
2N/A if (off > 0)
2N/A break;
2N/A }
2N/A
2N/A /* are we rebooting to a GRUB menu entry? */
2N/A if (isdigit(bargs[0])) {
2N/A int entry = strtol(bargs, NULL, 10);
2N/A (void) snprintf(cmdbuf, sizeof (cmdbuf),
2N/A "/usr/sbin/bootadm set-menu default=%d",
2N/A entry);
2N/A } else {
2N/A (void) snprintf(cmdbuf, sizeof (cmdbuf),
2N/A "/usr/sbin/bootadm -m update_temp "
2N/A "-o %s%s%s", quote, &bargs[off], quote);
2N/A }
2N/A (void) system(cmdbuf);
2N/A }
2N/A check_archive_update();
2N/A }
2N/A
2N/A return (__uadmin(cmd, fcn, mdep));
2N/A}