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
load_scf(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
check_archive_update(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
legal_arg(char * bargs)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
uadmin(int cmd,int fcn,uintptr_t mdep)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