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