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 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25
26
27 /*
28 * Module: zones.c
29 * Group: libinstzones
30 * Description: Provide "zones" interface for install consolidation code
31 *
32 * Public Methods:
33 *
34 * _z_close_file_descriptors - close a file descriptor "a_fd" not in the
35 * list "a_fds"
36 * _z_echo - Output an interactive message if interaction is enabled
37 * _z_echoDebug - Output a debugging message if debugging is enabled
38 * _z_is_directory - determine if specified path exists and is a directory
39 * _z_program_error - Output an error message to the appropriate destinations
40 * _z_pluginCatchSigint - SIGINT/SIGHUP interrupt handler
41 * _z_running_in_global_zone - Determine if this process is running in the
42 * global zone
43 * _z_zones_are_implemented - Determine if zones are supported by the
44 * current system
45 * _z_brands_are_implemented - determine if branded zones are implemented on
46 * this system
47 */
48
49 /*
50 * System includes
51 */
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <ctype.h>
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <string.h>
61 #include <strings.h>
62 #include <sys/stat.h>
63 #include <stdarg.h>
64 #include <limits.h>
65 #include <errno.h>
66 #include <signal.h>
67 #include <stropts.h>
68 #include <libintl.h>
69 #include <locale.h>
70 #include <assert.h>
71 #include <dlfcn.h>
72
73 /*
74 * local includes
75 */
76
77 #include "instzones_lib.h"
78 #include "zones_strings.h"
79
80 /*
81 * Private structures
82 */
83
84 /*
85 * these dynamic libraries are required in order to use the branded zones
86 * functionality. If these libraries are not available at runtime,
87 * then the zones we find are assumed to be native zones.
88 */
89
90 #define BRAND1_LIBRARY "libbrand.so.1"
91 #define BRAND_LIBRARY "libbrand.so"
92
93 /*
94 * Library Function Prototypes
95 */
96
97 /*
98 * Local Function Prototypes
99 */
100
101 static void error_and_exit(int error_num);
102
103 static void (*fatal_err_func)() = &error_and_exit;
104
105 /* ----------------------- private functions -------------------------- */
106 /*
107 * error_and_exit()
108 * Abort routine. An exit code of '2' is used by all applications
109 * to indicate a non-recoverable fatal error.
110 * Parameters:
111 * error_num - error index number:
112 * ERR_MALLOC_FAIL
113 * Return:
114 * none
115 * Status:
116 * private
117 */
118 static void
error_and_exit(int error_num)119 error_and_exit(int error_num)
120 {
121 if (error_num == ERR_MALLOC_FAIL)
122 (void) fprintf(stderr, "Allocation of memory failed\n");
123 else
124 (void) fprintf(stderr, "ERROR: code %d\n", error_num);
125 exit(2);
126 }
127
128 /*
129 * *****************************************************************************
130 * global external (public) functions
131 * *****************************************************************************
132 */
133
134 /*
135 * Name: _z_close_file_descriptors
136 * Description: close a file descriptor "a_fd" not in the list "a_fds"
137 * This function is called from the fdwalk() library function.
138 * If the file descriptor passed in is NOT in the list passed in,
139 * the file is closed.
140 * Arguments: a_fds - [RO, *RO] - (void *)
141 * Pointer to list of file descriptors to keep open
142 * a_fd - [RO, *RO] - (int)
143 * File descriptor to check
144 * Returns: int
145 * 0 - success
146 */
147
148 int
_z_close_file_descriptors(void * a_fds,int a_fd)149 _z_close_file_descriptors(void *a_fds, int a_fd)
150 {
151 int *fds;
152 int i;
153
154 /* do not close standard input, output, or error file descriptors */
155
156 if (a_fd == STDIN_FILENO || a_fd == STDOUT_FILENO ||
157 a_fd == STDERR_FILENO) {
158 return (0);
159 }
160
161 /* if no file descriptor retention list, close this file */
162
163 if (a_fds == (void *)NULL) {
164 (void) close(a_fd);
165 return (0);
166 }
167
168 /*
169 * retention list provided, skip this descriptor if its in the list
170 */
171
172 fds = (int *)a_fds;
173
174 for (i = 0; fds[i] != -1; i++) {
175 if (fds[i] == a_fd) {
176 return (0);
177 }
178 }
179
180 /* this descriptor not in retention list - close this file */
181
182 (void) close(a_fd);
183
184 return (0);
185 }
186
187 /*
188 * Name: _z_echo
189 * Synopsis: Output an interactive message if interaction is enabled
190 * Description: Main method for outputting an interactive message; call to
191 * output interactive message if interation has not been disabled
192 * by a previous call to echoSetFlag(0).
193 * Arguments: format - [RO, RO*] (char *)
194 * printf-style format for debugging message to be output
195 * VARG_LIST - [RO] (?)
196 * arguments as appropriate to 'format' specified
197 * Returns: void
198 */
199
200 /*PRINTFLIKE1*/
201 void
_z_echo(char * a_format,...)202 _z_echo(char *a_format, ...)
203 {
204 va_list ap;
205 char message[MAX_MESSAGE_SIZE];
206
207 /* entry assertions */
208
209 assert(a_format != NULL);
210
211 /* return if no progerr function registered */
212
213 if (_z_global_data._z_echo == NULL) {
214 return;
215 }
216
217 /* capture message */
218
219 va_start(ap, a_format);
220 (void) vsnprintf(message, sizeof (message), a_format, ap);
221 va_end(ap);
222
223 /* pass message to registered function */
224
225 (_z_global_data._z_echo)("%s", message);
226 }
227
228 /*
229 * Name: _z_echoDebug
230 * Synopsis: Output a debugging message if debugging is enabled
231 * Description: Main method for outputting a debugging message; call to
232 * output debugging message if debugging has been enabled
233 * by a previous call to _z_echoDebugSetFlag(1).
234 * Arguments: format - [RO, RO*] (char *)
235 * printf-style format for debugging message to be output
236 * VARG_LIST - [RO] (?)
237 * arguments as appropriate to 'format' specified
238 * Returns: void
239 * NOTE: format of message will be:
240 * # [ aaa bbb ccc ] message
241 * where: aaa - process i.d.
242 * bbb - zone i.d.
243 * ccc - name of program
244 * for example:
245 * # [ 25685 0 pkgadd ] unable to get package list
246 */
247
248 /*PRINTFLIKE1*/
249 void
_z_echoDebug(char * a_format,...)250 _z_echoDebug(char *a_format, ...)
251 {
252 va_list ap;
253 char message[MAX_MESSAGE_SIZE];
254
255 /* entry assertions */
256
257 assert(a_format != NULL);
258
259 /* return if no progerr function registered */
260
261 if (_z_global_data._z_echo_debug == NULL) {
262 return;
263 }
264
265 /* capture message */
266
267 va_start(ap, a_format);
268 (void) vsnprintf(message, sizeof (message), a_format, ap);
269 va_end(ap);
270
271 /* pass message to registered function */
272
273 (_z_global_data._z_echo_debug)("%s", message);
274 }
275
276 /*
277 * Name: _z_is_directory
278 * Description: determine if specified path exists and is a directory
279 * Arguments: path - pointer to string representing the path to verify
280 * returns: 0 - directory exists
281 * 1 - directory does not exist or is not a directory
282 * NOTE: errno is set appropriately
283 */
284
285 int
_z_is_directory(char * path)286 _z_is_directory(char *path)
287 {
288 struct stat statbuf;
289
290 /* entry assertions */
291
292 assert(path != NULL);
293 assert(*path != '\0');
294
295 /* return error if path does not exist */
296
297 if (stat(path, &statbuf) != 0) {
298 return (1);
299 }
300
301 /* return error if path is not a directory */
302
303 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
304 errno = ENOTDIR;
305 return (1);
306 }
307
308 /* path exists and is a directory */
309
310 return (0);
311 }
312
313 /*
314 * Name: _z_pluginCatchSigint
315 * Synopsis: SIGINT/SIGHUP interrupt handler
316 * Description: Catch the "SIGINT" and "SIGHUP" signals:
317 * -> increment _z_SigReceived global variable
318 * -> propagate signal to "_z_ChildProcessId" if registered (!= -1)
319 * Arguments: signo - [RO, *RO] - (int)
320 * Signal number that was caught
321 * Returns: void
322 */
323
324 void
_z_sig_trap(int a_signo)325 _z_sig_trap(int a_signo)
326 {
327 /* bump signals received count */
328
329 _z_global_data._z_SigReceived++;
330
331 /* if child process registered, propagate signal to child */
332
333 if (_z_global_data._z_ChildProcessId > 0) {
334 (void) kill(_z_global_data._z_ChildProcessId, a_signo);
335 }
336 }
337
338 /*
339 * Name: _z_program_error
340 * Description: Output an error message to the appropriate destinations
341 * Arguments: format - [RO, RO*] (char *)
342 * printf-style format for debugging message to be output
343 * VARG_LIST - [RO] (?)
344 * arguments as appropriate to 'format' specified
345 * Returns: void
346 * NOTE: format of message will be:
347 * [aaa: ] ERROR: message
348 * where: aaa - program name (if set)
349 * message - results of format and arguments
350 * for example:
351 * ERROR: unable to get package list
352 */
353
354 /*PRINTFLIKE1*/
355 void
_z_program_error(char * a_format,...)356 _z_program_error(char *a_format, ...)
357 {
358 va_list ap;
359 char message[MAX_MESSAGE_SIZE];
360
361 /* entry assertions */
362
363 assert(a_format != NULL);
364
365 /* return if no progerr function registered */
366
367 if (_z_global_data._z_progerr == NULL) {
368 return;
369 }
370
371 /* capture message */
372
373 va_start(ap, a_format);
374 (void) vsnprintf(message, sizeof (message), a_format, ap);
375 va_end(ap);
376
377 /* pass message to registered function */
378
379 (_z_global_data._z_progerr)(MSG_PROG_ERR, message);
380 }
381
382 /*
383 * Name: _z_running_in_global_zone
384 * Synopsis: Determine if this process is running in the global zone
385 * Arguments: void
386 * Returns: boolean_t
387 * == B_TRUE - this process is running in the global zone
388 * == B_FALSE - this process is running in a nonglobal zone
389 */
390
391 boolean_t
_z_running_in_global_zone(void)392 _z_running_in_global_zone(void)
393 {
394 zoneid_t zoneid = (zoneid_t)-1;
395
396 /*
397 * if zones are not implemented, there is no way to tell if zones
398 * are supported or not - in this case, we can only be running in the
399 * global zone (since non-global zones cannot exist) so return TRUE
400 */
401
402 if (z_zones_are_implemented() == B_FALSE) {
403 return (B_TRUE);
404 }
405
406 /* get the zone i.d. of the current zone */
407
408 zoneid = getzoneid();
409
410 /* return TRUE if this is the global zone i.d. */
411
412 if (zoneid == GLOBAL_ZONEID) {
413 return (B_TRUE);
414 }
415
416 /* return FALSE - not in the global zone */
417
418 return (B_FALSE);
419 }
420
421 /*
422 * Name: _z_zones_are_implemented
423 * Synopsis: Determine if zones are supported by the current system
424 * Arguments: void
425 * Returns: boolean_t
426 * == B_TRUE - zones are supported
427 * == B_FALSE - zones are not supported
428 */
429
430 boolean_t
_z_zones_are_implemented(void)431 _z_zones_are_implemented(void)
432 {
433 void *libptr = NULL;
434
435 /* locate zone cfg library */
436
437 libptr = dlopen(ZONECFG_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
438 if (libptr == (void *)NULL) {
439 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, ZONECFG_LIBRARY, dlerror());
440 libptr = dlopen(ZONECFG1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
441 }
442
443 /* return false if library not available */
444
445 if (libptr == (void *)NULL) {
446 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, ZONECFG1_LIBRARY,
447 dlerror());
448 return (B_FALSE);
449 }
450
451 /* library available - close handle */
452
453 (void) dlclose(libptr);
454
455 /* locate contract filesystem library */
456
457 libptr = dlopen(CONTRACT_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
458 if (libptr == (void *)NULL) {
459 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, CONTRACT_LIBRARY,
460 dlerror());
461 libptr = dlopen(CONTRACT1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
462 }
463
464 /* return false if library not available */
465
466 if (libptr == (void *)NULL) {
467 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, CONTRACT1_LIBRARY,
468 dlerror());
469 return (B_FALSE);
470 }
471
472 /* library available - close handle */
473
474 (void) dlclose(libptr);
475
476 /* return success */
477
478 return (B_TRUE);
479 }
480
481 boolean_t
_z_brands_are_implemented(void)482 _z_brands_are_implemented(void)
483 {
484 void *libptr;
485
486 /* locate brand library */
487
488 libptr = dlopen(BRAND_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
489 if (libptr == NULL) {
490 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, BRAND_LIBRARY, dlerror());
491 libptr = dlopen(BRAND1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
492 }
493
494 /* return false if library not available */
495
496 if (libptr == NULL) {
497 _z_echoDebug(DBG_LIBRARY_NOT_FOUND, BRAND1_LIBRARY, dlerror());
498 return (B_FALSE);
499 }
500
501 /* library available - close handle */
502
503 (void) dlclose(libptr);
504
505 /* return success */
506
507 return (B_TRUE);
508 }
509
510 /*
511 * z_calloc()
512 * Allocate 'size' bytes from the heap using calloc()
513 * Parameters:
514 * size - number of bytes to allocate
515 * Return:
516 * NULL - calloc() failure
517 * void * - pointer to allocated structure
518 * Status:
519 * public
520 */
521 void *
_z_calloc(size_t size)522 _z_calloc(size_t size)
523 {
524 void * tmp;
525
526 if ((tmp = (void *) malloc(size)) == NULL) {
527 fatal_err_func(ERR_MALLOC_FAIL);
528 return (NULL);
529 }
530
531 (void) memset(tmp, 0, size);
532 return (tmp);
533 }
534
535 /*
536 * z_malloc()
537 * Alloc 'size' bytes from heap using malloc()
538 * Parameters:
539 * size - number of bytes to malloc
540 * Return:
541 * NULL - malloc() failure
542 * void * - pointer to allocated structure
543 * Status:
544 * public
545 */
546 void *
_z_malloc(size_t size)547 _z_malloc(size_t size)
548 {
549 void *tmp;
550
551 if ((tmp = (void *) malloc(size)) == NULL) {
552 fatal_err_func(ERR_MALLOC_FAIL);
553 return (NULL);
554 } else
555 return (tmp);
556 }
557
558 /*
559 * _z_realloc()
560 * Calls realloc() with the specfied parameters. _z_realloc()
561 * checks for realloc failures and adjusts the return value
562 * automatically.
563 * Parameters:
564 * ptr - pointer to existing data block
565 * size - number of bytes additional
566 * Return:
567 * NULL - realloc() failed
568 * void * - pointer to realloc'd structured
569 * Status:
570 * public
571 */
572 void *
_z_realloc(void * ptr,size_t size)573 _z_realloc(void *ptr, size_t size)
574 {
575 void *tmp;
576
577 if ((tmp = (void *)realloc(ptr, size)) == (void *)NULL) {
578 fatal_err_func(ERR_MALLOC_FAIL);
579 return ((void *)NULL);
580 } else
581 return (tmp);
582 }
583
584 /*
585 * z_strdup()
586 * Allocate space for the string from the heap, copy 'str' into it,
587 * and return a pointer to it.
588 * Parameters:
589 * str - string to duplicate
590 * Return:
591 * NULL - duplication failed or 'str' was NULL
592 * char * - pointer to newly allocated/initialized structure
593 * Status:
594 * public
595 */
596 void *
_z_strdup(char * str)597 _z_strdup(char *str)
598 {
599 char *tmp;
600
601 if (str == NULL)
602 return ((char *)NULL);
603
604 if ((tmp = strdup(str)) == NULL) {
605 fatal_err_func(ERR_MALLOC_FAIL);
606 return ((char *)NULL);
607 } else
608 return (tmp);
609 }
610