dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / allocate / allocate.c
blob68715f63caa368bf401a1e59a1a37dc029eae128
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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 #include <ctype.h>
37 #include <fcntl.h>
38 #include <nss_dbdefs.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/wait.h>
42 #include <zone.h>
43 #include <bsm/devalloc.h>
44 #include "allocate.h"
46 #if !defined(TEXT_DOMAIN)
47 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
48 #endif
50 #define ALLOC "allocate"
51 #define DEALLOC "deallocate"
52 #define LIST "list_devices"
54 extern void audit_allocate_argv(int, int, char *[]);
55 extern int audit_allocate_record(int);
57 static int windowing = 0;
58 static int wdwmsg(char *name, char *msg);
60 static void
61 usage(int func)
63 char *use[5];
65 use[0] = gettext("allocate "
66 "[-s] [-U uname] [-F] device|-g dev-type");
67 use[1] = gettext("deallocate [-s] [-F] device|-c dev-class");
68 use[2] = gettext("deallocate [-s] -I");
69 use[3] = gettext("list_devices "
70 "[-s] [-U uid] -l|-n|-u [device]");
71 use[4] = gettext("list_devices "
72 "[-s] [-U uid] [-l|-n|-u] -c dev-class");
74 switch (func) {
75 case 0:
76 (void) fprintf(stderr, "%s\n", use[0]);
77 break;
78 case 1:
79 (void) fprintf(stderr, "%s\n%s\n",
80 use[1], use[2]);
81 break;
82 case 2:
83 (void) fprintf(stderr, "%s\n%s\n",
84 use[3], use[4]);
85 break;
86 default:
87 (void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
88 use[0], use[1], use[2], use[3], use[4]);
90 exit(1);
93 void
94 print_error(int error, char *name)
96 char *msg;
97 char msgbuf[200];
99 switch (error) {
100 case ALLOCUERR:
101 msg = gettext("Specified device is allocated to another user.");
102 break;
103 case CHOWNERR:
104 msg = gettext("Failed to chown.");
105 break;
106 case CLEANERR:
107 msg = gettext("Unable to clean up device.");
108 break;
109 case CNTDEXECERR:
110 msg = gettext(
111 "Can't exec device-clean program for specified device.");
112 break;
113 case CNTFRCERR:
114 msg = gettext("Can't force deallocate specified device.");
115 break;
116 case DACACCERR:
117 msg = gettext(
118 "Can't access DAC file for the device specified.");
119 break;
120 case DAOFFERR:
121 msg = gettext(
122 "Device allocation feature is not activated "
123 "on this system.");
124 break;
125 case DAUTHERR:
126 msg = gettext("Device not allocatable.");
127 break;
128 case DEFATTRSERR:
129 msg = gettext("No default attributes for specified "
130 "device type.");
131 break;
132 case DEVLKERR:
133 msg = gettext("Concurrent operations for specified device, "
134 "try later.");
135 break;
136 case DEVLONGERR:
137 msg = gettext("Device name is too long.");
138 break;
139 case DEVNALLOCERR:
140 msg = gettext("Device not allocated.");
141 break;
142 case DEVNAMEERR:
143 msg = gettext("Device name error.");
144 break;
145 case DEVSTATEERR:
146 msg = gettext("Device specified is in allocate error state.");
147 break;
148 case DEVZONEERR:
149 msg = gettext("Can't find name of the zone to which "
150 "device is allocated.");
151 break;
152 case DSPMISSERR:
153 msg = gettext(
154 "Device special file(s) missing for specified device.");
155 break;
156 case LOGINDEVPERMERR:
157 msg = gettext("Device controlled by logindevperm(4)");
158 break;
159 case NODAERR:
160 msg = gettext("No entry for specified device.");
161 break;
162 case NODMAPERR:
163 msg = gettext("No entry for specified device.");
164 break;
165 case PREALLOCERR:
166 msg = gettext("Device already allocated.");
167 break;
168 case SETACLERR:
169 msg = gettext("Failed to set ACL.");
170 break;
171 case UAUTHERR:
172 msg = gettext(
173 "User lacks authorization required for this operation.");
174 break;
175 case ZONEERR:
176 msg = gettext("Failed to configure device in zone.");
177 break;
178 default:
179 msg = gettext("Unknown error code.");
180 break;
183 if (windowing) {
184 (void) snprintf(msgbuf, sizeof (msgbuf), "%s: %s\n", name, msg);
185 (void) wdwmsg(name, msgbuf);
186 } else {
187 (void) fprintf(stderr, "%s: %s\n", name, msg);
188 (void) fflush(stderr);
192 char *newenv[] = {"PATH=/usr/bin:/usr/sbin",
193 NULL, /* for LC_ALL */
194 NULL, /* for LC_COLLATE */
195 NULL, /* for LC_CTYPE */
196 NULL, /* for LC_MESSAGES */
197 NULL, /* for LC_NUMERIC */
198 NULL, /* for LC_TIME */
199 NULL, /* for LANG */
200 NULL
203 static char *
204 getenvent(char *name, char *env[])
206 for (; *env != NULL; env++) {
207 if (strncmp(*env, name, strlen(name)) == 0)
208 return (*env);
210 return (NULL);
214 main(int argc, char *argv[], char *envp[])
216 char *name, *env;
217 int func = -1, optflg = 0, error = 0, c;
218 zoneid_t zoneid;
219 uid_t uid;
220 char *uname = NULL, *device = NULL, *zonename = NULL;
221 char *zname;
222 char pw_buf[NSS_BUFLEN_PASSWD];
223 struct passwd pw_ent;
224 int env_num = 1; /* PATH= is 0 entry */
225 #ifdef DEBUG
226 struct stat statbuf;
227 #endif
229 (void) setlocale(LC_ALL, "");
230 (void) textdomain(TEXT_DOMAIN);
233 * get all enviroment variables
234 * which affect on internationalization.
236 env = getenvent("LC_ALL=", envp);
237 if (env != NULL)
238 newenv[env_num++] = env;
239 env = getenvent("LC_COLLATE=", envp);
240 if (env != NULL)
241 newenv[env_num++] = env;
242 env = getenvent("LC_CTYPE=", envp);
243 if (env != NULL)
244 newenv[env_num++] = env;
245 env = getenvent("LC_MESSAGES=", envp);
246 if (env != NULL)
247 newenv[env_num++] = env;
248 env = getenvent("LC_NUMERIC=", envp);
249 if (env != NULL)
250 newenv[env_num++] = env;
251 env = getenvent("LC_TIME=", envp);
252 if (env != NULL)
253 newenv[env_num++] = env;
254 env = getenvent("LANG=", envp);
255 if (env != NULL)
256 newenv[env_num] = env;
258 if ((name = strrchr(argv[0], '/')) == NULL)
259 name = argv[0];
260 else
261 name++;
263 if (strcmp(name, ALLOC) == 0)
264 func = 0;
265 else if (strcmp(name, DEALLOC) == 0)
266 func = 1;
267 else if (strcmp(name, LIST) == 0)
268 func = 2;
269 else
270 usage(-1);
272 audit_allocate_argv(func, argc, argv);
274 if (func == 0) { /* allocate */
275 while ((c = getopt(argc, argv, "g:sFU:")) != -1) {
276 switch (c) {
277 case 'g':
278 optflg |= TYPE;
279 device = optarg;
280 break;
281 case 's':
282 optflg |= SILENT;
283 break;
284 case 'F':
285 optflg |= FORCE;
286 break;
287 case 'U':
288 optflg |= USERNAME;
289 uname = optarg;
290 break;
291 case '?':
292 default :
293 usage(func);
298 * allocate(1) must be supplied with one device argument
300 if (device && ((argc - optind) >= 1))
301 usage(func);
302 if (device == NULL) {
303 if ((argc - optind) != 1)
304 usage(func);
305 device = argv[optind];
309 else if (func == 1) { /* deallocate */
310 while ((c = getopt(argc, argv, "c:sFI")) != -1) {
311 switch (c) {
312 case 'c':
313 if (optflg & (TYPE | FORCE_ALL))
314 usage(func);
315 optflg |= CLASS;
316 device = optarg;
317 break;
318 case 's':
319 optflg |= SILENT;
320 break;
321 case 'F':
322 if (optflg & FORCE_ALL)
323 usage(func);
324 optflg |= FORCE;
325 break;
326 case 'I':
327 if (optflg & (CLASS | TYPE | FORCE))
328 usage(func);
329 optflg |= FORCE_ALL;
330 break;
331 case '?':
332 default :
333 usage(func);
338 * deallocate(1) must be supplied with one device
339 * argument unless the '-I' argument is supplied
341 if (device || (optflg & FORCE_ALL)) {
342 if ((argc - optind) >= 1)
343 usage(func);
344 } else if (device == NULL) {
345 if ((argc - optind) != 1)
346 usage(func);
347 device = argv[optind];
351 else if (func == 2) { /* list_devices */
352 while ((c = getopt(argc, argv, "c:lnsuU:")) != -1) {
353 switch (c) {
354 case 'c':
355 optflg |= CLASS;
356 device = optarg;
357 break;
358 case 'l':
359 if (optflg & (LISTFREE | LISTALLOC | LISTDEFS))
360 usage(func);
361 optflg |= LISTALL;
362 break;
363 case 'n':
364 if (optflg & (LISTALL | LISTALLOC | LISTDEFS))
365 usage(func);
366 optflg |= LISTFREE;
367 break;
368 case 's':
369 optflg |= SILENT;
370 break;
371 case 'u':
372 if (optflg & (LISTALL | LISTFREE | LISTDEFS))
373 usage(func);
374 optflg |= LISTALLOC;
375 break;
376 case 'U':
377 if (optflg & LISTDEFS)
378 usage(func);
379 optflg |= USERID;
380 uid = atoi(optarg);
381 break;
382 case '?':
383 default :
384 usage(func);
388 if (!(optflg & (LISTALL | LISTFREE | LISTALLOC))) {
389 if (!(optflg & CLASS))
390 usage(func);
394 * list_devices(1) takes an optional device argument.
396 if (device && ((argc - optind) >= 1))
397 usage(func);
398 if (device == NULL) {
399 if ((argc - optind) == 1)
400 device = argv[optind];
401 else if ((argc - optind) > 1)
402 usage(func);
406 if (optflg & USERNAME) {
407 struct passwd *result;
408 getpwnam_r(uname, &pw_ent, pw_buf, sizeof (pw_buf), &result);
409 if (!result) {
410 (void) fprintf(stderr,
411 gettext("Invalid user name -- %s -- \n"), uname);
412 exit(1);
414 uid = pw_ent.pw_uid;
415 } else if (optflg & USERID) {
416 struct passwd *result;
417 getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf), &result);
418 if (!result) {
419 (void) fprintf(stderr,
420 gettext("Invalid user ID -- %d -- \n"), uid);
421 exit(1);
423 uid = pw_ent.pw_uid;
424 } else {
426 * caller's uid is the default if no user specified.
428 uid = getuid();
432 * global zone is the default if no zonename specified.
434 if (zonename == NULL) {
435 zonename = zname;
436 } else {
437 if (zone_get_id(zonename, &zoneid) != 0) {
438 (void) fprintf(stderr,
439 gettext("Invalid zone name -- %s -- \n"), zonename);
440 exit(1);
444 if (func == 0)
445 error = allocate(optflg, uid, device, zonename);
446 else if (func == 1)
447 error = deallocate(optflg, uid, device, zonename);
448 else if (func == 2)
449 error = list_devices(optflg, uid, device, zonename);
451 (void) audit_allocate_record(error);
453 if (error) {
454 if (!(optflg & SILENT))
455 print_error(error, name);
456 exit(error);
459 return (0);
463 * Display error message via /etc/security/lib/wdwmsg script
465 static int
466 wdwmsg(char *name, char *msg)
468 pid_t child_pid;
469 pid_t wait_pid;
470 int child_status;
472 /* Fork a child */
473 switch (child_pid = fork()) {
474 case -1: /* FAILURE */
475 return (-1);
476 break;
478 case 0: /* CHILD */
479 (void) execl("/etc/security/lib/wdwmsg", "wdwmsg", msg,
480 name, "OK", NULL);
481 /* If exec failed, send message to stderr */
482 (void) fprintf(stderr, "%s", msg);
483 return (-1);
485 default: /* PARENT */
486 /* Wait for child to exit */
487 wait_pid = waitpid(child_pid, &child_status, 0);
488 if ((wait_pid < 0) && (errno == ECHILD))
489 return (0);
490 if ((wait_pid < 0) || (wait_pid != child_pid))
491 return (-1);
492 if (WIFEXITED(child_status))
493 return (WEXITSTATUS(child_status));
494 if (WIFSIGNALED(child_status))
495 return (WTERMSIG(child_status));
496 return (0);