1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2267 dp * Common Development and Distribution License (the "License"). 6 2267 dp * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 5891 raf 22 0 stevel /* 23 9160 Sherry * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel 28 0 stevel /* 29 0 stevel * Wrapper function to implement reboot w/ arguments on x86 30 0 stevel * platforms. Extract reboot arguments and place them in 31 0 stevel * in a transient entry in /[stub]boot/grub/menu.lst 32 0 stevel * All other commands are passed through. 33 0 stevel */ 34 6812 raf #include "lint.h" 35 10054 Jan #include "mtlib.h" 36 0 stevel #include <fcntl.h> 37 0 stevel #include <ctype.h> 38 0 stevel #include <stdio.h> 39 0 stevel #include <stdlib.h> 40 0 stevel #include <sys/types.h> 41 0 stevel #include <sys/stat.h> 42 0 stevel #include <sys/uadmin.h> 43 0 stevel #include <unistd.h> 44 7656 Sherry #include <strings.h> 45 5891 raf #include <pthread.h> 46 2267 dp #include <zone.h> 47 10052 Gangadhar #include <libscf.h> 48 10054 Jan #include <thread.h> 49 10054 Jan #include <dlfcn.h> 50 10054 Jan #include <atomic.h> 51 10054 Jan 52 10054 Jan /* 53 10054 Jan * Pull in the following three interfaces from libscf without introducing 54 10054 Jan * a dependency on it, which since libscf depends on libc would be circular: 55 10054 Jan * 56 10054 Jan * scf_simple_prop_get 57 10054 Jan * scf_simple_prop_next_boolean 58 10054 Jan * scf_simple_prop_free 59 10054 Jan */ 60 10054 Jan typedef scf_simple_prop_t *(*scf_simple_prop_get_t)(scf_handle_t *, 61 10054 Jan const char *, const char *, const char *); 62 10054 Jan static scf_simple_prop_get_t real_scf_simple_prop_get = NULL; 63 10054 Jan typedef uint8_t *(*scf_simple_prop_next_boolean_t)(scf_simple_prop_t *); 64 10054 Jan static scf_simple_prop_next_boolean_t real_scf_simple_prop_next_boolean = NULL; 65 10054 Jan typedef void (*scf_simple_prop_free_t)(scf_simple_prop_t *); 66 10054 Jan static scf_simple_prop_free_t real_scf_simple_prop_free = NULL; 67 10054 Jan static mutex_t scf_lock = DEFAULTMUTEX; 68 10054 Jan 69 10054 Jan static void 70 10054 Jan load_scf(void) 71 10054 Jan { 72 10054 Jan void *scf_handle = dlopen("libscf.so.1", RTLD_LAZY); 73 10054 Jan scf_simple_prop_get_t scf_simple_prop_get = (scf_handle == NULL)? NULL : 74 10054 Jan (scf_simple_prop_get_t)dlsym(scf_handle, "scf_simple_prop_get"); 75 10054 Jan scf_simple_prop_next_boolean_t scf_simple_prop_next_boolean = 76 10054 Jan (scf_handle == NULL)? NULL : 77 10054 Jan (scf_simple_prop_next_boolean_t)dlsym(scf_handle, 78 10054 Jan "scf_simple_prop_next_boolean"); 79 10054 Jan scf_simple_prop_free_t scf_simple_prop_free = 80 10054 Jan (scf_handle == NULL)? NULL : 81 10054 Jan (scf_simple_prop_free_t)dlsym(scf_handle, "scf_simple_prop_free"); 82 10054 Jan 83 10054 Jan lmutex_lock(&scf_lock); 84 10054 Jan if (real_scf_simple_prop_get == NULL || 85 10054 Jan real_scf_simple_prop_next_boolean == NULL || 86 10054 Jan real_scf_simple_prop_free == NULL) { 87 10054 Jan if (scf_simple_prop_get == NULL) 88 10054 Jan real_scf_simple_prop_get = (scf_simple_prop_get_t)(-1); 89 10054 Jan else { 90 10054 Jan real_scf_simple_prop_get = scf_simple_prop_get; 91 10054 Jan scf_handle = NULL; /* don't dlclose it */ 92 10054 Jan } 93 10054 Jan if (scf_simple_prop_next_boolean == NULL) 94 10054 Jan real_scf_simple_prop_next_boolean = 95 10054 Jan (scf_simple_prop_next_boolean_t)(-1); 96 10054 Jan else { 97 10054 Jan real_scf_simple_prop_next_boolean = 98 10054 Jan scf_simple_prop_next_boolean; 99 10054 Jan scf_handle = NULL; /* don't dlclose it */ 100 10054 Jan } 101 10054 Jan if (scf_simple_prop_free == NULL) 102 10054 Jan real_scf_simple_prop_free = 103 10054 Jan (scf_simple_prop_free_t)(-1); 104 10054 Jan else { 105 10054 Jan real_scf_simple_prop_free = scf_simple_prop_free; 106 10054 Jan scf_handle = NULL; /* don't dlclose it */ 107 10054 Jan } 108 10054 Jan membar_producer(); 109 10054 Jan } 110 10054 Jan lmutex_unlock(&scf_lock); 111 10054 Jan 112 10054 Jan if (scf_handle) 113 10054 Jan (void) dlclose(scf_handle); 114 10054 Jan } 115 10054 Jan 116 10054 Jan static void 117 10054 Jan check_archive_update(void) 118 10054 Jan { 119 10054 Jan scf_simple_prop_t *prop = NULL; 120 10054 Jan boolean_t update_flag = B_FALSE; 121 10054 Jan char *fmri = "svc:/system/boot-config:default"; 122 10054 Jan uint8_t *ret_val = NULL; 123 10054 Jan 124 10054 Jan if (real_scf_simple_prop_get == NULL || 125 10054 Jan real_scf_simple_prop_next_boolean == NULL || 126 10054 Jan real_scf_simple_prop_free == NULL) { 127 10054 Jan load_scf(); 128 10054 Jan } 129 10054 Jan if (real_scf_simple_prop_get == (scf_simple_prop_get_t)(-1) || 130 10054 Jan real_scf_simple_prop_next_boolean == 131 10054 Jan (scf_simple_prop_next_boolean_t)(-1) || 132 10054 Jan real_scf_simple_prop_free == (scf_simple_prop_free_t)(-1)) { 133 10054 Jan return; 134 10054 Jan } 135 10054 Jan 136 10054 Jan prop = real_scf_simple_prop_get(NULL, fmri, "config", 137 10054 Jan "uadmin_boot_archive_sync"); 138 10054 Jan if (prop) { 139 10054 Jan if ((ret_val = real_scf_simple_prop_next_boolean(prop)) != 140 10054 Jan NULL) 141 10054 Jan update_flag = (*ret_val == 0) ? B_FALSE : 142 10054 Jan B_TRUE; 143 10054 Jan real_scf_simple_prop_free(prop); 144 10054 Jan } 145 10054 Jan 146 10054 Jan if (update_flag == B_TRUE) 147 10054 Jan (void) system("/sbin/bootadm update-archive"); 148 10054 Jan } 149 0 stevel 150 0 stevel static int 151 0 stevel legal_arg(char *bargs) 152 0 stevel { 153 0 stevel int i; 154 0 stevel 155 2267 dp for (i = 0; i < BOOTARGS_MAX; i++, bargs++) { 156 0 stevel if (*bargs == 0 && i > 0) 157 0 stevel return (i); 158 0 stevel if (!isprint(*bargs)) 159 0 stevel break; 160 0 stevel } 161 0 stevel return (-1); 162 0 stevel } 163 0 stevel 164 0 stevel static char quote[] = "\'"; 165 0 stevel 166 0 stevel int 167 0 stevel uadmin(int cmd, int fcn, uintptr_t mdep) 168 0 stevel { 169 0 stevel extern int __uadmin(int cmd, int fcn, uintptr_t mdep); 170 0 stevel char *bargs, cmdbuf[256]; 171 0 stevel struct stat sbuf; 172 0 stevel char *altroot; 173 0 stevel 174 0 stevel bargs = (char *)mdep; 175 7656 Sherry 176 2267 dp if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID && 177 2267 dp (cmd == A_SHUTDOWN || cmd == A_REBOOT)) { 178 7656 Sherry int off = 0; 179 7656 Sherry 180 0 stevel switch (fcn) { 181 0 stevel case AD_IBOOT: 182 0 stevel case AD_SBOOT: 183 0 stevel case AD_SIBOOT: 184 0 stevel /* 185 0 stevel * These functions fabricate appropriate bootargs. 186 0 stevel * If bootargs are passed in, map these functions 187 0 stevel * to AD_BOOT. 188 0 stevel */ 189 0 stevel if (bargs == 0) { 190 0 stevel switch (fcn) { 191 0 stevel case AD_IBOOT: 192 0 stevel bargs = "-a"; 193 0 stevel break; 194 0 stevel case AD_SBOOT: 195 0 stevel bargs = "-s"; 196 0 stevel break; 197 0 stevel case AD_SIBOOT: 198 0 stevel bargs = "-sa"; 199 0 stevel break; 200 0 stevel } 201 0 stevel } 202 0 stevel /*FALLTHROUGH*/ 203 0 stevel case AD_BOOT: 204 7656 Sherry case AD_FASTREBOOT: 205 0 stevel if (bargs == 0) 206 0 stevel break; /* no args */ 207 0 stevel if (legal_arg(bargs) < 0) 208 0 stevel break; /* bad args */ 209 0 stevel 210 5891 raf /* avoid cancellation in system() */ 211 5891 raf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 212 5891 raf NULL); 213 5891 raf 214 0 stevel /* check for /stubboot */ 215 0 stevel if (stat("/stubboot/boot/grub/menu.lst", &sbuf) == 0) { 216 0 stevel altroot = "-R /stubboot "; 217 0 stevel } else { 218 0 stevel altroot = ""; 219 0 stevel } 220 0 stevel 221 7656 Sherry if (fcn == AD_FASTREBOOT) { 222 7656 Sherry char *newarg, *head; 223 7656 Sherry char bargs_scratch[BOOTARGS_MAX]; 224 7656 Sherry 225 7656 Sherry bzero(bargs_scratch, BOOTARGS_MAX); 226 7656 Sherry 227 7656 Sherry bcopy(bargs, bargs_scratch, strlen(bargs)); 228 7656 Sherry head = bargs_scratch; 229 7656 Sherry newarg = strtok(bargs_scratch, " "); 230 7656 Sherry 231 9160 Sherry if (newarg == NULL || newarg[0] == '-') 232 7656 Sherry break; 233 7656 Sherry 234 7656 Sherry /* First argument is rootdir */ 235 9160 Sherry if (strncmp(&newarg[strlen(newarg)-4], 236 7656 Sherry "unix", 4) != 0) { 237 7656 Sherry newarg = strtok(NULL, " "); 238 7656 Sherry off = newarg - head; 239 7656 Sherry } 240 7656 Sherry 241 7656 Sherry /* 242 7656 Sherry * If we are using alternate root via 243 7656 Sherry * mountpoint or a different BE, don't 244 7656 Sherry * bother to update the temp menu entry. 245 7656 Sherry */ 246 7656 Sherry if (off > 0) 247 7656 Sherry break; 248 7656 Sherry } 249 7656 Sherry 250 0 stevel /* are we rebooting to a GRUB menu entry? */ 251 0 stevel if (isdigit(bargs[0])) { 252 0 stevel int entry = strtol(bargs, NULL, 10); 253 0 stevel (void) snprintf(cmdbuf, sizeof (cmdbuf), 254 0 stevel "/sbin/bootadm set-menu %sdefault=%d", 255 0 stevel altroot, entry); 256 0 stevel } else { 257 0 stevel (void) snprintf(cmdbuf, sizeof (cmdbuf), 258 0 stevel "/sbin/bootadm -m update_temp %s" 259 7656 Sherry "-o %s%s%s", altroot, quote, 260 7656 Sherry &bargs[off], quote); 261 0 stevel } 262 0 stevel (void) system(cmdbuf); 263 0 stevel } 264 10054 Jan check_archive_update(); 265 0 stevel } 266 0 stevel return (__uadmin(cmd, fcn, mdep)); 267 0 stevel } 268