xref: /illumos-gate/usr/src/lib/libinstzones/common/zones_utils.c (revision 55d6cb5d63bcf69dfa47b8c41c770a2d34f169b0)
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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 *
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