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