xref: /illumos-gate/usr/src/lib/libc/i386/sys/uadmin.c (revision 4ed6ceb3)
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