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