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 */
347257d1b4Sraf #include "lint.h"
35*4ed6ceb3SJan Setje-Eilers #include "mtlib.h"
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/uadmin.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
4419397407SSherry Moore #include <strings.h>
45a574db85Sraf #include <pthread.h>
463f2f09c1Sdp #include <zone.h>
47050c4bfeSGangadhar Mylapuram #include <libscf.h>
48*4ed6ceb3SJan Setje-Eilers #include <thread.h>
49*4ed6ceb3SJan Setje-Eilers #include <dlfcn.h>
50*4ed6ceb3SJan Setje-Eilers #include <atomic.h>
51*4ed6ceb3SJan Setje-Eilers
52*4ed6ceb3SJan Setje-Eilers /*
53*4ed6ceb3SJan Setje-Eilers * Pull in the following three interfaces from libscf without introducing
54*4ed6ceb3SJan Setje-Eilers * a dependency on it, which since libscf depends on libc would be circular:
55*4ed6ceb3SJan Setje-Eilers *
56*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_get
57*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_next_boolean
58*4ed6ceb3SJan Setje-Eilers * scf_simple_prop_free
59*4ed6ceb3SJan Setje-Eilers */
60*4ed6ceb3SJan Setje-Eilers typedef scf_simple_prop_t *(*scf_simple_prop_get_t)(scf_handle_t *,
61*4ed6ceb3SJan Setje-Eilers const char *, const char *, const char *);
62*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_get_t real_scf_simple_prop_get = NULL;
63*4ed6ceb3SJan Setje-Eilers typedef uint8_t *(*scf_simple_prop_next_boolean_t)(scf_simple_prop_t *);
64*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_next_boolean_t real_scf_simple_prop_next_boolean = NULL;
65*4ed6ceb3SJan Setje-Eilers typedef void (*scf_simple_prop_free_t)(scf_simple_prop_t *);
66*4ed6ceb3SJan Setje-Eilers static scf_simple_prop_free_t real_scf_simple_prop_free = NULL;
67*4ed6ceb3SJan Setje-Eilers static mutex_t scf_lock = DEFAULTMUTEX;
68*4ed6ceb3SJan Setje-Eilers
69*4ed6ceb3SJan Setje-Eilers static void
load_scf(void)70*4ed6ceb3SJan Setje-Eilers load_scf(void)
71*4ed6ceb3SJan Setje-Eilers {
72*4ed6ceb3SJan Setje-Eilers void *scf_handle = dlopen("libscf.so.1", RTLD_LAZY);
73*4ed6ceb3SJan Setje-Eilers scf_simple_prop_get_t scf_simple_prop_get = (scf_handle == NULL)? NULL :
74*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_get_t)dlsym(scf_handle, "scf_simple_prop_get");
75*4ed6ceb3SJan Setje-Eilers scf_simple_prop_next_boolean_t scf_simple_prop_next_boolean =
76*4ed6ceb3SJan Setje-Eilers (scf_handle == NULL)? NULL :
77*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)dlsym(scf_handle,
78*4ed6ceb3SJan Setje-Eilers "scf_simple_prop_next_boolean");
79*4ed6ceb3SJan Setje-Eilers scf_simple_prop_free_t scf_simple_prop_free =
80*4ed6ceb3SJan Setje-Eilers (scf_handle == NULL)? NULL :
81*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_free_t)dlsym(scf_handle, "scf_simple_prop_free");
82*4ed6ceb3SJan Setje-Eilers
83*4ed6ceb3SJan Setje-Eilers lmutex_lock(&scf_lock);
84*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == NULL ||
85*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean == NULL ||
86*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == NULL) {
87*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_get == NULL)
88*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_get = (scf_simple_prop_get_t)(-1);
89*4ed6ceb3SJan Setje-Eilers else {
90*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_get = scf_simple_prop_get;
91*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */
92*4ed6ceb3SJan Setje-Eilers }
93*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_next_boolean == NULL)
94*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean =
95*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)(-1);
96*4ed6ceb3SJan Setje-Eilers else {
97*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean =
98*4ed6ceb3SJan Setje-Eilers scf_simple_prop_next_boolean;
99*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */
100*4ed6ceb3SJan Setje-Eilers }
101*4ed6ceb3SJan Setje-Eilers if (scf_simple_prop_free == NULL)
102*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free =
103*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_free_t)(-1);
104*4ed6ceb3SJan Setje-Eilers else {
105*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free = scf_simple_prop_free;
106*4ed6ceb3SJan Setje-Eilers scf_handle = NULL; /* don't dlclose it */
107*4ed6ceb3SJan Setje-Eilers }
108*4ed6ceb3SJan Setje-Eilers membar_producer();
109*4ed6ceb3SJan Setje-Eilers }
110*4ed6ceb3SJan Setje-Eilers lmutex_unlock(&scf_lock);
111*4ed6ceb3SJan Setje-Eilers
112*4ed6ceb3SJan Setje-Eilers if (scf_handle)
113*4ed6ceb3SJan Setje-Eilers (void) dlclose(scf_handle);
114*4ed6ceb3SJan Setje-Eilers }
115*4ed6ceb3SJan Setje-Eilers
116*4ed6ceb3SJan Setje-Eilers static void
check_archive_update(void)117*4ed6ceb3SJan Setje-Eilers check_archive_update(void)
118*4ed6ceb3SJan Setje-Eilers {
119*4ed6ceb3SJan Setje-Eilers scf_simple_prop_t *prop = NULL;
120*4ed6ceb3SJan Setje-Eilers boolean_t update_flag = B_FALSE;
121*4ed6ceb3SJan Setje-Eilers char *fmri = "svc:/system/boot-config:default";
122*4ed6ceb3SJan Setje-Eilers uint8_t *ret_val = NULL;
123*4ed6ceb3SJan Setje-Eilers
124*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == NULL ||
125*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean == NULL ||
126*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == NULL) {
127*4ed6ceb3SJan Setje-Eilers load_scf();
128*4ed6ceb3SJan Setje-Eilers }
129*4ed6ceb3SJan Setje-Eilers if (real_scf_simple_prop_get == (scf_simple_prop_get_t)(-1) ||
130*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_next_boolean ==
131*4ed6ceb3SJan Setje-Eilers (scf_simple_prop_next_boolean_t)(-1) ||
132*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free == (scf_simple_prop_free_t)(-1)) {
133*4ed6ceb3SJan Setje-Eilers return;
134*4ed6ceb3SJan Setje-Eilers }
135*4ed6ceb3SJan Setje-Eilers
136*4ed6ceb3SJan Setje-Eilers prop = real_scf_simple_prop_get(NULL, fmri, "config",
137*4ed6ceb3SJan Setje-Eilers "uadmin_boot_archive_sync");
138*4ed6ceb3SJan Setje-Eilers if (prop) {
139*4ed6ceb3SJan Setje-Eilers if ((ret_val = real_scf_simple_prop_next_boolean(prop)) !=
140*4ed6ceb3SJan Setje-Eilers NULL)
141*4ed6ceb3SJan Setje-Eilers update_flag = (*ret_val == 0) ? B_FALSE :
142*4ed6ceb3SJan Setje-Eilers B_TRUE;
143*4ed6ceb3SJan Setje-Eilers real_scf_simple_prop_free(prop);
144*4ed6ceb3SJan Setje-Eilers }
145*4ed6ceb3SJan Setje-Eilers
146*4ed6ceb3SJan Setje-Eilers if (update_flag == B_TRUE)
147*4ed6ceb3SJan Setje-Eilers (void) system("/sbin/bootadm update-archive");
148*4ed6ceb3SJan Setje-Eilers }
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate static int
legal_arg(char * bargs)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
uadmin(int cmd,int fcn,uintptr_t mdep)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();
265050c4bfeSGangadhar Mylapuram }
2667c478bd9Sstevel@tonic-gate return (__uadmin(cmd, fcn, mdep));
2677c478bd9Sstevel@tonic-gate }
268