xref: /illumos-gate/usr/src/cmd/allocate/allocate.c (revision 622200ad88c6c6382403a01985a94e22484baac6)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <errno.h>
30 #include <locale.h>
31 #include <pwd.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include <sys/types.h>
38 
39 #include "allocate.h"
40 
41 #if !defined(TEXT_DOMAIN)
42 #define	TEXT_DOMAIN "SUNW_OST_OSCMD"
43 #endif
44 
45 extern void audit_allocate_argv(int, int, char *[]);
46 extern int audit_allocate_record(int);
47 
48 static void
49 usage(int func)
50 {
51 	char *use[7];
52 
53 	use[0] = gettext("allocate [-s] [-U uname] [-F] device");
54 	use[1] = gettext("allocate [-s] [-U uname] -g dev_type");
55 	use[2] = gettext("deallocate [-s] [-F] device");
56 	use[3] = gettext("deallocate [-s] -I");
57 	use[4] = gettext("list_devices [-s] [-U uid] -l [device]");
58 	use[5] = gettext("list_devices [-s] [-U uid] -n [device]");
59 	use[6] = gettext("list_devices [-s] [-U uid] -u [device]");
60 
61 	switch (func) {
62 		case 0:
63 			(void) fprintf(stderr, "%s\n%s\n", use[0], use[1]);
64 			break;
65 		case 1:
66 			(void) fprintf(stderr, "%s\n%s\n", use[2], use[3]);
67 			break;
68 		case 2:
69 			(void) fprintf(stderr, "%s\n%s\n%s\n", use[4], use[5],
70 			    use[6]);
71 			break;
72 		default:
73 			(void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
74 				use[0], use[1], use[2], use[3], use[4]);
75 	}
76 	exit(1);
77 }
78 
79 static void
80 print_error(int error, char *name)
81 {
82 	char *msg;
83 
84 	switch (error) {
85 	case SYSERROR:
86 		msg = gettext("Unknown System error.");
87 		break;
88 	case IMPORT_ERR:
89 		msg = gettext(
90 		    "User lacks authorization required for this operation.");
91 		break;
92 	case NODAENT:
93 		msg = gettext(
94 		    "No device allocate file entry for specified device.");
95 		break;
96 	case NODMAPENT:
97 		msg = gettext(
98 		    "No device maps file entry for specified device.");
99 		break;
100 	case DACLCK:
101 		msg = gettext("Concurrent operations for specified device, "
102 		    "try later.");
103 		break;
104 	case DACACC:
105 		msg = gettext(
106 		    "Can't access DAC file for the device specified.");
107 		break;
108 	case DEVLST:
109 		msg = gettext(
110 		    "Could not use device list for the device specified.");
111 		break;
112 	case NALLOCU:
113 		msg = gettext("Specified device is allocated to another user.");
114 		break;
115 	case NOTAUTH:
116 		msg = gettext("Not authorized for specified operation.");
117 		break;
118 	case CNTFRC:
119 		msg = gettext("Can't force deallocate specified device.");
120 		break;
121 	case CNTDEXEC:
122 		msg = gettext(
123 		    "Can't exec device-clean program for specified device.");
124 		break;
125 	case NO_DEVICE:
126 		msg = gettext(
127 		    "Can't find a device of type requested to allocate.");
128 		break;
129 	case DSPMISS:
130 		msg = gettext(
131 		    "Device special file(s) missing for specified device.");
132 		break;
133 	case ALLOCERR:
134 		msg = gettext("Device specified is in allocate error state.");
135 		break;
136 	case CHOWN_PERR:
137 		msg = gettext("Process lacks privilege required to chown().");
138 		break;
139 	case ALLOC:
140 		msg = gettext("Device already allocated.");
141 		break;
142 	case ALLOC_OTHER:
143 		msg = gettext("Device allocated to another user.");
144 		break;
145 	case NALLOC:
146 		msg = gettext("Device not allocated.");
147 		break;
148 	case AUTHERR:
149 		msg = gettext("Device not allocatable.");
150 		break;
151 	case CLEAN_ERR:
152 		msg = gettext("Unable to clean up the device.");
153 		break;
154 	case SETACL_PERR:
155 		msg = gettext("Process lacks privilege required to set ACL.");
156 		break;
157 	case DEVNAME_ERR:
158 		msg = gettext("Error forming device name.");
159 		break;
160 	case DEVNAME_TOOLONG:
161 		msg = gettext("Device name is too long.");
162 		break;
163 	default:
164 		msg = gettext("Unknown error code.");
165 		break;
166 	}
167 
168 	(void) fprintf(stderr, "%s: %s\n", name, msg);
169 	(void) fflush(stderr);
170 }
171 
172 char *newenv[] = {"PATH=/usr/bin:/usr/sbin",
173 			NULL,			/* for LC_ALL		*/
174 			NULL,			/* for LC_COLLATE	*/
175 			NULL,			/* for LC_CTYPE		*/
176 			NULL,			/* for LC_MESSAGES	*/
177 			NULL,			/* for LC_NUMERIC	*/
178 			NULL,			/* for LC_TIME		*/
179 			NULL,			/* for LANG		*/
180 			NULL
181 };
182 
183 static char *
184 getenvent(char *name, char *env[])
185 {
186 	for (; *env != NULL; env++) {
187 		if (strncmp(*env, name, strlen(name)) == 0)
188 			return (*env);
189 	}
190 	return (NULL);
191 }
192 
193 int
194 main(int argc, char *argv[], char *envp[])
195 {
196 	char	*name, *env;
197 	int	func = -1, optflg = 0, error = 0, c;
198 	uid_t	uid = getuid();
199 	char	*uname = NULL, *device = NULL;
200 	struct passwd *pw_ent;
201 	int env_num = 1;	/* PATH= is 0 entry */
202 
203 	(void) setlocale(LC_ALL, "");
204 	(void) textdomain(TEXT_DOMAIN);
205 
206 	/*
207 	 * get all enviroment variables
208 	 * which affect on internationalization.
209 	 */
210 	env = getenvent("LC_ALL=", envp);
211 	if (env != NULL)
212 		newenv[env_num++] = env;
213 	env = getenvent("LC_COLLATE=", envp);
214 	if (env != NULL)
215 		newenv[env_num++] = env;
216 	env = getenvent("LC_CTYPE=", envp);
217 	if (env != NULL)
218 		newenv[env_num++] = env;
219 	env = getenvent("LC_MESSAGES=", envp);
220 	if (env != NULL)
221 		newenv[env_num++] = env;
222 	env = getenvent("LC_NUMERIC=", envp);
223 	if (env != NULL)
224 		newenv[env_num++] = env;
225 	env = getenvent("LC_TIME=", envp);
226 	if (env != NULL)
227 		newenv[env_num++] = env;
228 	env = getenvent("LANG=", envp);
229 	if (env != NULL)
230 		newenv[env_num] = env;
231 
232 	if ((name = strrchr(argv[0], '/')) == NULL)
233 		name = argv[0];
234 	else
235 		name++;
236 
237 	if (strcmp(name, "allocate") == 0)
238 		func = 0;
239 	else if (strcmp(name, "deallocate") == 0)
240 		func = 1;
241 	else if (strcmp(name, "list_devices") == 0)
242 		func = 2;
243 	else {
244 		usage(ALL);
245 	}
246 
247 	audit_allocate_argv(func, argc, argv);
248 
249 	if (func == 0) {	/* allocate */
250 		while ((c = getopt(argc, argv, "sU:Fg")) != -1) {
251 			switch (c) {
252 			case 's':
253 				optflg |= SILENT;
254 				break;
255 			case 'U':
256 				optflg |= USERNAME;
257 				uname = optarg;
258 				break;
259 			case 'g':
260 				optflg |= TYPE;
261 				break;
262 			case 'F':
263 				optflg |= FORCE;
264 				break;
265 			case '?':
266 			default :
267 				usage(func);
268 			}
269 		}
270 
271 		if ((optflg & TYPE) && (optflg & FORCE))
272 			usage(func);
273 
274 		/*
275 		 * allocate(1) must be supplied with one device argument
276 		 */
277 		if ((argc - optind) != 1) {
278 			usage(func);
279 		} else {
280 			device = argv[optind];
281 		}
282 	}
283 
284 	else if (func == 1) {	/* deallocate */
285 		while ((c = getopt(argc, argv, "sFI")) != -1) {
286 			switch (c) {
287 			case 's':
288 				optflg |= SILENT;
289 				break;
290 			case 'F':
291 				optflg |= FORCE;
292 				break;
293 			case 'I':
294 				optflg |= FORCE_ALL;
295 				break;
296 			case '?':
297 			default :
298 				usage(func);
299 			}
300 		}
301 
302 		if ((optflg & FORCE) && (optflg & FORCE_ALL))
303 			usage(func);
304 
305 		/*
306 		 * deallocate(1) must be supplied with one device
307 		 * argument unless the '-I' argument is supplied
308 		 */
309 		if (!(optflg & FORCE_ALL)) {
310 			if ((argc - optind) != 1) {
311 				usage(func);
312 			} else {
313 				device = argv[optind];
314 			}
315 		} else {
316 			if ((argc - optind) >= 1) {
317 				usage(func);
318 			}
319 		}
320 	}
321 
322 	else if (func == 2) {	/* list_devices */
323 		while ((c = getopt(argc, argv, "sU:lnu")) != -1) {
324 			switch (c) {
325 			case 's':
326 				optflg |= SILENT;
327 				break;
328 			case 'U':
329 				optflg |= USERID;
330 				uid = atoi(optarg);
331 				break;
332 			case 'l':
333 				optflg |= LIST;
334 				break;
335 			case 'n':
336 				optflg |= FREE;
337 				break;
338 			case 'u':
339 				optflg |= CURRENT;
340 				break;
341 			case '?':
342 			default :
343 				usage(func);
344 			}
345 		}
346 
347 		if (((optflg & LIST) && (optflg & FREE)) ||
348 		    ((optflg & LIST) && (optflg & CURRENT)) ||
349 		    ((optflg & FREE) && (optflg & CURRENT)) ||
350 		    (!(optflg & (LIST | FREE | CURRENT))))
351 			usage(func);
352 
353 		/*
354 		 * list_devices(1) takes an optional device argument
355 		 */
356 		if ((argc - optind) == 1) {
357 			device = argv[optind];
358 		} else {
359 			if ((argc - optind) > 1) {
360 				usage(func);
361 			}
362 		}
363 	}
364 
365 	if (optflg & USERNAME) {
366 		if ((pw_ent = getpwnam(uname)) == NULL) {
367 			(void) fprintf(stderr, gettext(
368 			    "Invalid user name -- %s -- \n"), uname);
369 			exit(1);
370 		}
371 		uid = pw_ent->pw_uid;
372 	}
373 
374 	if (optflg & USERID) {
375 		if ((pw_ent = getpwuid(uid)) == NULL) {
376 			(void) fprintf(stderr, gettext(
377 			    "Invalid user ID -- %d -- \n"), uid);
378 			exit(1);
379 		}
380 		uid = pw_ent->pw_uid;
381 	}
382 
383 	if (func == 0) {
384 		error = allocate(optflg, uid, device);
385 	} else if (func == 1) {
386 		error = deallocate(optflg, uid, device);
387 	} else if (func == 2) {
388 		error = list_devices(optflg, uid, device);
389 	}
390 
391 	(void) audit_allocate_record(error);
392 
393 	if (error) {
394 		if (!(optflg & SILENT))
395 			print_error(error, name);
396 		exit(error);
397 	}
398 
399 	return (0);
400 }
401