xref: /illumos-gate/usr/src/lib/libc/amd64/sys/uadmin.c (revision 753a6d45)
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 <fcntl.h>
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/uadmin.h>
43 #include <unistd.h>
44 #include <strings.h>
45 #include <pthread.h>
46 #include <zone.h>
47 
48 static int
49 legal_arg(char *bargs)
50 {
51 	int i;
52 
53 	for (i = 0; i < BOOTARGS_MAX; i++, bargs++) {
54 		if (*bargs == 0 && i > 0)
55 			return (i);
56 		if (!isprint(*bargs))
57 			break;
58 	}
59 	return (-1);
60 }
61 
62 static char quote[] = "\'";
63 
64 int
65 uadmin(int cmd, int fcn, uintptr_t mdep)
66 {
67 	extern int __uadmin(int cmd, int fcn, uintptr_t mdep);
68 	char *bargs, cmdbuf[256];
69 	struct stat sbuf;
70 	char *altroot;
71 
72 	bargs = (char *)mdep;
73 
74 	if (geteuid() == 0 && getzoneid() == GLOBAL_ZONEID &&
75 	    (cmd == A_SHUTDOWN || cmd == A_REBOOT)) {
76 		int off = 0;
77 
78 		switch (fcn) {
79 		case AD_IBOOT:
80 		case AD_SBOOT:
81 		case AD_SIBOOT:
82 			/*
83 			 * These functions fabricate appropriate bootargs.
84 			 * If bootargs are passed in, map these functions
85 			 * to AD_BOOT.
86 			 */
87 			if (bargs == 0) {
88 				switch (fcn) {
89 				case AD_IBOOT:
90 					bargs = "-a";
91 					break;
92 				case AD_SBOOT:
93 					bargs = "-s";
94 					break;
95 				case AD_SIBOOT:
96 					bargs = "-sa";
97 					break;
98 				}
99 			}
100 			/*FALLTHROUGH*/
101 		case AD_BOOT:
102 		case AD_FASTREBOOT:
103 			if (bargs == 0)
104 				break;	/* no args */
105 			if (legal_arg(bargs) < 0)
106 				break;	/* bad args */
107 
108 			/* avoid cancellation in system() */
109 			(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
110 			    NULL);
111 
112 			/* check for /stubboot */
113 			if (stat("/stubboot/boot/grub/menu.lst", &sbuf) == 0) {
114 				altroot = "-R /stubboot ";
115 			} else {
116 				altroot = "";
117 			}
118 
119 			if (fcn == AD_FASTREBOOT) {
120 				char *newarg, *head;
121 				char bargs_scratch[BOOTARGS_MAX];
122 
123 				bzero(bargs_scratch, BOOTARGS_MAX);
124 
125 				bcopy(bargs, bargs_scratch, strlen(bargs));
126 				head = bargs_scratch;
127 				newarg = strtok(bargs_scratch, " ");
128 
129 				if (newarg == NULL || newarg[0] == '-')
130 					break;
131 
132 				/* First argument is rootdir */
133 				if (strncmp(&newarg[strlen(newarg)-4],
134 				    "unix", 4) != 0) {
135 					newarg = strtok(NULL, " ");
136 					off = newarg - head;
137 				}
138 
139 				/*
140 				 * If we are using alternate root via
141 				 * mountpoint or a different BE, don't
142 				 * bother to update the temp menu entry.
143 				 */
144 				if (off > 0)
145 					break;
146 			}
147 
148 			/* are we rebooting to a GRUB menu entry? */
149 			if (isdigit(bargs[0])) {
150 				int entry = strtol(bargs, NULL, 10);
151 				(void) snprintf(cmdbuf, sizeof (cmdbuf),
152 				    "/sbin/bootadm set-menu %sdefault=%d",
153 				    altroot, entry);
154 			} else {
155 				(void) snprintf(cmdbuf, sizeof (cmdbuf),
156 				    "/sbin/bootadm -m update_temp %s"
157 				    "-o %s%s%s", altroot, quote,
158 				    &bargs[off], quote);
159 			}
160 			(void) system(cmdbuf);
161 		}
162 	}
163 
164 	return (__uadmin(cmd, fcn, mdep));
165 }
166