17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53f2f09c1Sdp * Common Development and Distribution License (the "License"). 63f2f09c1Sdp * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21a574db85Sraf 227c478bd9Sstevel@tonic-gate /* 23753a6d45SSherry Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Wrapper function to implement reboot w/ arguments on x86 307c478bd9Sstevel@tonic-gate * platforms. Extract reboot arguments and place them in 317c478bd9Sstevel@tonic-gate * in a transient entry in /[stub]boot/grub/menu.lst 327c478bd9Sstevel@tonic-gate * All other commands are passed through. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357257d1b4Sraf #include "lint.h" 36*4ed6ceb3SJan Setje-Eilers #include "mtlib.h" 377c478bd9Sstevel@tonic-gate #include <fcntl.h> 387c478bd9Sstevel@tonic-gate #include <ctype.h> 397c478bd9Sstevel@tonic-gate #include <stdio.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <sys/types.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/uadmin.h> 447c478bd9Sstevel@tonic-gate #include <unistd.h> 4519397407SSherry Moore #include <strings.h> 46a574db85Sraf #include <pthread.h> 473f2f09c1Sdp #include <zone.h> 48050c4bfeSGangadhar Mylapuram #include <libscf.h> 49*4ed6ceb3SJan Setje-Eilers #include <thread.h> 50*4ed6ceb3SJan Setje-Eilers #include <dlfcn.h> 51*4ed6ceb3SJan Setje-Eilers #include <atomic.h> 527c478bd9Sstevel@tonic-gate 53*4ed6ceb3SJan Setje-Eilers /* 54*4ed6ceb3SJan Setje-Eilers * Pull in the following three interfaces from libscf without introducing 55*4ed6ceb3SJan Setje-Eilers * a dependency on it, which since libscf depends on libc would be circular: 56*4ed6ceb3SJan Setje-Eilers * 57*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_get 58*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_next_boolean 59*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_free 60*4ed6ceb3SJan Setje-Eilers */ 61*4ed6ceb3SJan Setje-Eilers typedef scf_simple_prop_t *(*scf_simple_prop_get_t)(scf_handle_t *, 62*4ed6ceb3SJan Setje-Eilers const char *, const char *, const char *); 63*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_get_t real_scf_simple_prop_get = NULL; 64*4ed6ceb3SJan Setje-Eilers typedef uint8_t *(*scf_simple_prop_next_boolean_t)(scf_simple_prop_t *); 65*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_next_boolean_t real_scf_simple_prop_next_boolean = NULL; 66*4ed6ceb3SJan Setje-Eilers typedef void (*scf_simple_prop_free_t)(scf_simple_prop_t *); 67*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_free_t real_scf_simple_prop_free = NULL; 68*4ed6ceb3SJan Setje-Eilers static mutex_t scf_lock = DEFAULTMUTEX; 69*4ed6ceb3SJan Setje-Eilers 70*4ed6ceb3SJan Setje-Eilers static void 71*4ed6ceb3SJan Setje-Eilers load_scf(void) 72*4ed6ceb3SJan Setje-Eilers { 73*4ed6ceb3SJan Setje-Eilers void *scf_handle = dlopen("libscf.so.1", RTLD_LAZY); 74*4ed6ceb3SJan Setje-Eilers scf_simple_prop_get_t scf_simple_prop_get = (scf_handle == NULL)? NULL : 75*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_get_t)dlsym(scf_handle, "scf_simple_prop_get"); 76*4ed6ceb3SJan Setje-Eilers scf_simple_prop_next_boolean_t scf_simple_prop_next_boolean = 77*4ed6ceb3SJan Setje-Eilers (scf_handle == NULL)? NULL : 78*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)dlsym(scf_handle, 79*4ed6ceb3SJan Setje-Eilers "scf_simple_prop_next_boolean"); 80*4ed6ceb3SJan Setje-Eilers scf_simple_prop_free_t scf_simple_prop_free = 81*4ed6ceb3SJan Setje-Eilers (scf_handle == NULL)? NULL : 82*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_free_t)dlsym(scf_handle, "scf_simple_prop_free"); 83*4ed6ceb3SJan Setje-Eilers 84*4ed6ceb3SJan Setje-Eilers lmutex_lock(&scf_lock); 85*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == NULL || 86*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean == NULL || 87*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == NULL) { 88*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_get == NULL) 89*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_get = (scf_simple_prop_get_t)(-1); 90*4ed6ceb3SJan Setje-Eilers else { 91*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_get = scf_simple_prop_get; 92*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */ 93*4ed6ceb3SJan Setje-Eilers } 94*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_next_boolean == NULL) 95*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean = 96*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)(-1); 97*4ed6ceb3SJan Setje-Eilers else { 98*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean = 99*4ed6ceb3SJan Setje-Eilers scf_simple_prop_next_boolean; 100*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */ 101*4ed6ceb3SJan Setje-Eilers } 102*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_free == NULL) 103*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free = 104*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_free_t)(-1); 105*4ed6ceb3SJan Setje-Eilers else { 106*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free = scf_simple_prop_free; 107*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */ 108*4ed6ceb3SJan Setje-Eilers } 109*4ed6ceb3SJan Setje-Eilers membar_producer(); 110*4ed6ceb3SJan Setje-Eilers } 111*4ed6ceb3SJan Setje-Eilers lmutex_unlock(&scf_lock); 112*4ed6ceb3SJan Setje-Eilers 113*4ed6ceb3SJan Setje-Eilers if (scf_handle) 114*4ed6ceb3SJan Setje-Eilers (void) dlclose(scf_handle); 115*4ed6ceb3SJan Setje-Eilers } 116*4ed6ceb3SJan Setje-Eilers 117*4ed6ceb3SJan Setje-Eilers static void 118*4ed6ceb3SJan Setje-Eilers check_archive_update(void) 119*4ed6ceb3SJan Setje-Eilers { 120*4ed6ceb3SJan Setje-Eilers scf_simple_prop_t *prop = NULL; 121*4ed6ceb3SJan Setje-Eilers boolean_t update_flag = B_FALSE; 122*4ed6ceb3SJan Setje-Eilers char *fmri = "svc:/system/boot-config:default"; 123*4ed6ceb3SJan Setje-Eilers uint8_t *ret_val = NULL; 124*4ed6ceb3SJan Setje-Eilers 125*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == NULL || 126*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean == NULL || 127*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == NULL) { 128*4ed6ceb3SJan Setje-Eilers load_scf(); 129*4ed6ceb3SJan Setje-Eilers } 130*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == (scf_simple_prop_get_t)(-1) || 131*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean == 132*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)(-1) || 133*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == (scf_simple_prop_free_t)(-1)) { 134*4ed6ceb3SJan Setje-Eilers return; 135*4ed6ceb3SJan Setje-Eilers } 136*4ed6ceb3SJan Setje-Eilers 137*4ed6ceb3SJan Setje-Eilers prop = real_scf_simple_prop_get(NULL, fmri, "config", 138*4ed6ceb3SJan Setje-Eilers "uadmin_boot_archive_sync"); 139*4ed6ceb3SJan Setje-Eilers if (prop) { 140*4ed6ceb3SJan Setje-Eilers if ((ret_val = real_scf_simple_prop_next_boolean(prop)) != 141*4ed6ceb3SJan Setje-Eilers NULL) 142*4ed6ceb3SJan Setje-Eilers update_flag = (*ret_val == 0) ? B_FALSE : 143*4ed6ceb3SJan Setje-Eilers B_TRUE; 144*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free(prop); 145*4ed6ceb3SJan Setje-Eilers } 146*4ed6ceb3SJan Setje-Eilers 147*4ed6ceb3SJan Setje-Eilers if (update_flag == B_TRUE) 148*4ed6ceb3SJan Setje-Eilers (void) system("/sbin/bootadm update-archive"); 149*4ed6ceb3SJan Setje-Eilers } 1507c478bd9Sstevel@tonic-gate static int 1517c478bd9Sstevel@tonic-gate legal_arg(char *bargs) 1527c478bd9Sstevel@tonic-gate { 1537c478bd9Sstevel@tonic-gate int i; 1547c478bd9Sstevel@tonic-gate 1553f2f09c1Sdp for (i = 0; i < BOOTARGS_MAX; i++, bargs++) { 1567c478bd9Sstevel@tonic-gate if (*bargs == 0 && i > 0) 1577c478bd9Sstevel@tonic-gate return (i); 1587c478bd9Sstevel@tonic-gate if (!isprint(*bargs)) 1597c478bd9Sstevel@tonic-gate break; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate return (-1); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate static char quote[] = "\'"; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate int 1677c478bd9Sstevel@tonic-gate uadmin(int cmd, int fcn, uintptr_t mdep) 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate extern int __uadmin(int cmd, int fcn, uintptr_t mdep); 1707c478bd9Sstevel@tonic-gate char *bargs, cmdbuf[256]; 1717c478bd9Sstevel@tonic-gate struct stat sbuf; 1727c478bd9Sstevel@tonic-gate char *altroot; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate bargs = (char *)mdep; 17519397407SSherry Moore 1763f2f09c1Sdp if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID && 1773f2f09c1Sdp (cmd == A_SHUTDOWN || cmd == A_REBOOT)) { 17819397407SSherry Moore int off = 0; 17919397407SSherry Moore 1807c478bd9Sstevel@tonic-gate switch (fcn) { 1817c478bd9Sstevel@tonic-gate case AD_IBOOT: 1827c478bd9Sstevel@tonic-gate case AD_SBOOT: 1837c478bd9Sstevel@tonic-gate case AD_SIBOOT: 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * These functions fabricate appropriate bootargs. 1867c478bd9Sstevel@tonic-gate * If bootargs are passed in, map these functions 1877c478bd9Sstevel@tonic-gate * to AD_BOOT. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate if (bargs == 0) { 1907c478bd9Sstevel@tonic-gate switch (fcn) { 1917c478bd9Sstevel@tonic-gate case AD_IBOOT: 1927c478bd9Sstevel@tonic-gate bargs = "-a"; 1937c478bd9Sstevel@tonic-gate break; 1947c478bd9Sstevel@tonic-gate case AD_SBOOT: 1957c478bd9Sstevel@tonic-gate bargs = "-s"; 1967c478bd9Sstevel@tonic-gate break; 1977c478bd9Sstevel@tonic-gate case AD_SIBOOT: 1987c478bd9Sstevel@tonic-gate bargs = "-sa"; 1997c478bd9Sstevel@tonic-gate break; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 2037c478bd9Sstevel@tonic-gate case AD_BOOT: 20419397407SSherry Moore case AD_FASTREBOOT: 2057c478bd9Sstevel@tonic-gate if (bargs == 0) 2067c478bd9Sstevel@tonic-gate break; /* no args */ 2077c478bd9Sstevel@tonic-gate if (legal_arg(bargs) < 0) 2087c478bd9Sstevel@tonic-gate break; /* bad args */ 2097c478bd9Sstevel@tonic-gate 210a574db85Sraf /* avoid cancellation in system() */ 211a574db85Sraf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 212a574db85Sraf NULL); 213a574db85Sraf 2147c478bd9Sstevel@tonic-gate /* check for /stubboot */ 2157c478bd9Sstevel@tonic-gate if (stat("/stubboot/boot/grub/menu.lst", &sbuf) == 0) { 2167c478bd9Sstevel@tonic-gate altroot = "-R /stubboot "; 2177c478bd9Sstevel@tonic-gate } else { 2187c478bd9Sstevel@tonic-gate altroot = ""; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 22119397407SSherry Moore if (fcn == AD_FASTREBOOT) { 22219397407SSherry Moore char *newarg, *head; 22319397407SSherry Moore char bargs_scratch[BOOTARGS_MAX]; 22419397407SSherry Moore 22519397407SSherry Moore bzero(bargs_scratch, BOOTARGS_MAX); 22619397407SSherry Moore 22719397407SSherry Moore bcopy(bargs, bargs_scratch, strlen(bargs)); 22819397407SSherry Moore head = bargs_scratch; 22919397407SSherry Moore newarg = strtok(bargs_scratch, " "); 23019397407SSherry Moore 231753a6d45SSherry Moore if (newarg == NULL || newarg[0] == '-') 23219397407SSherry Moore break; 23319397407SSherry Moore 23419397407SSherry Moore /* First argument is rootdir */ 235753a6d45SSherry Moore if (strncmp(&newarg[strlen(newarg)-4], 23619397407SSherry Moore "unix", 4) != 0) { 23719397407SSherry Moore newarg = strtok(NULL, " "); 23819397407SSherry Moore off = newarg - head; 23919397407SSherry Moore } 24019397407SSherry Moore 24119397407SSherry Moore /* 24219397407SSherry Moore * If we are using alternate root via 24319397407SSherry Moore * mountpoint or a different BE, don't 24419397407SSherry Moore * bother to update the temp menu entry. 24519397407SSherry Moore */ 24619397407SSherry Moore if (off > 0) 24719397407SSherry Moore break; 24819397407SSherry Moore } 24919397407SSherry Moore 2507c478bd9Sstevel@tonic-gate /* are we rebooting to a GRUB menu entry? */ 2517c478bd9Sstevel@tonic-gate if (isdigit(bargs[0])) { 2527c478bd9Sstevel@tonic-gate int entry = strtol(bargs, NULL, 10); 2537c478bd9Sstevel@tonic-gate (void) snprintf(cmdbuf, sizeof (cmdbuf), 2547c478bd9Sstevel@tonic-gate "/sbin/bootadm set-menu %sdefault=%d", 2557c478bd9Sstevel@tonic-gate altroot, entry); 2567c478bd9Sstevel@tonic-gate } else { 2577c478bd9Sstevel@tonic-gate (void) snprintf(cmdbuf, sizeof (cmdbuf), 2587c478bd9Sstevel@tonic-gate "/sbin/bootadm -m update_temp %s" 25919397407SSherry Moore "-o %s%s%s", altroot, quote, 26019397407SSherry Moore &bargs[off], quote); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate (void) system(cmdbuf); 2637c478bd9Sstevel@tonic-gate } 264*4ed6ceb3SJan Setje-Eilers check_archive_update(); 2657c478bd9Sstevel@tonic-gate } 26619397407SSherry Moore 2677c478bd9Sstevel@tonic-gate return (__uadmin(cmd, fcn, mdep)); 2687c478bd9Sstevel@tonic-gate } 269