Print this page




 111                 return (NULL);
 112 
 113         if ((ze = malloc(sizeof (struct zoneent))) == NULL)
 114                 return (NULL);
 115 
 116         for (;;) {
 117                 if (fgets(buf, sizeof (buf), cookie) == NULL) {
 118                         free(ze);
 119                         return (NULL);
 120                 }
 121                 if ((cp = strpbrk(buf, "\r\n")) == NULL) {
 122                         /* this represents a line that's too long */
 123                         continue;
 124                 }
 125                 *cp = '\0';
 126                 cp = buf;
 127                 if (*cp == '#') {
 128                         /* skip comment lines */
 129                         continue;
 130                 }
 131 
 132                 /* zonename */
 133                 p = gettok(&cp);
 134                 if (*p == '\0' || strlen(p) >= ZONENAME_MAX) {
 135                         /*
 136                          * empty or very long zone names are not allowed
 137                          */
 138                         continue;
 139                 }
 140                 (void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
 141 
 142                 /* state */
 143                 p = gettok(&cp);
 144                 if (*p == '\0') {
 145                         /* state field should not be empty */
 146                         continue;
 147                 }
 148                 errno = 0;
 149                 if (strcmp(p, ZONE_STATE_STR_CONFIGURED) == 0) {
 150                         ze->zone_state = ZONE_STATE_CONFIGURED;
 151                 } else if (strcmp(p, ZONE_STATE_STR_INCOMPLETE) == 0) {
 152                         ze->zone_state = ZONE_STATE_INCOMPLETE;
 153                 } else if (strcmp(p, ZONE_STATE_STR_INSTALLED) == 0) {
 154                         ze->zone_state = ZONE_STATE_INSTALLED;
 155                 } else {
 156                         continue;
 157                 }
 158 
 159                 /* zonepath */
 160                 p = gettok(&cp);
 161                 if (strlen(p) >= MAXPATHLEN) {
 162                         /* very long paths are not allowed */
 163                         continue;
 164                 }
 165                 (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
 166 
 167                 /* uuid */
 168                 p = gettok(&cp);
 169                 if (uuid_parse(p, ze->zone_uuid) == -1)
 170                         uuid_clear(ze->zone_uuid);
 171 
 172                 /* brand [optional] */
 173                 p = gettok(&cp);
 174                 if (strlen(p) >= MAXNAMELEN) {
 175                         /* very long names are not allowed */
 176                         continue;
 177                 }
 178                 (void) strlcpy(ze->zone_brand, p, MAXNAMELEN);
 179 
 180                 /* IP type [optional] */
 181                 p = gettok(&cp);
 182                 if (strlen(p) >= MAXNAMELEN) {
 183                         /* very long names are not allowed */
 184                         continue;
 185                 }
 186                 ze->zone_iptype = ZS_SHARED;
 187                 if (*p == 'e') {
 188                         ze->zone_iptype = ZS_EXCLUSIVE;
 189                 }
 190 
 191                 /* debug ID [optional] */
 192                 p = gettok(&cp);
 193                 if (*p != '\0')
 194                         ze->zone_did = atoi(p);
 195 
 196                 break;
 197         }
 198 
 199         return (ze);
 200 }
 201 
 202 static boolean_t
 203 path_common(char *path, size_t path_size, const char *stem)
 204 {
 205         const char *native_root = zone_get_nroot();
 206 
 207         if (native_root == NULL || zonecfg_in_alt_root()) {
 208                 /*
 209                  * Do not prepend the native system root (e.g. "/native") if an
 210                  * alternative configuration root has been selected.
 211                  */
 212                 native_root = "";
 213         }
 214 
 215         return (snprintf(path, path_size, "%s%s%s", native_root, zonecfg_root,


 306  *
 307  * A zero-length ze->zone_path means leave the existing value
 308  * unchanged; this is only meaningful when operation == PZE_MODIFY
 309  * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
 310  *
 311  * A zero-length ze->zone_newname means leave the existing name
 312  * unchanged; otherwise the zone is renamed to zone_newname.  This is
 313  * only meaningful when operation == PZE_MODIFY.
 314  *
 315  * Locking and unlocking is done via the functions above.
 316  * The file itself is not modified in place; rather, a copy is made which
 317  * is modified, then the copy is atomically renamed back to the main file.
 318  */
 319 int
 320 putzoneent(struct zoneent *ze, zoneent_op_t operation)
 321 {
 322         FILE *index_file, *tmp_file;
 323         char buf[MAX_INDEX_LEN];
 324         int tmp_file_desc, lock_fd, err;
 325         boolean_t exist, need_quotes;
 326         char *cp, *tmpp;
 327         char tmp_path[MAXPATHLEN];
 328         char path[MAXPATHLEN];
 329         char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
 330         size_t namelen;
 331         const char *zone_name, *zone_state, *zone_path, *zone_uuid,
 332             *zone_brand = "", *zone_iptype;
 333         zoneid_t zone_did;
 334 
 335         assert(ze != NULL);
 336 
 337         /*
 338          * Don't allow modification of Global Zone entry
 339          * in index file
 340          */
 341         if ((operation == PZE_MODIFY) &&
 342             (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
 343                 return (Z_OK);
 344         }
 345 
 346         if (operation == PZE_ADD &&
 347             (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
 348                 return (Z_INVAL);
 349 
 350         if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
 351                 return (Z_INVAL);
 352 
 353         if ((lock_fd = lock_index_file()) == -1)


 366         }
 367         (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
 368         (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
 369         if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
 370                 (void) close(tmp_file_desc);
 371                 err = Z_MISC_FS;
 372                 goto error;
 373         }
 374         if (!get_index_path(path, sizeof (path))) {
 375                 err = Z_MISC_FS;
 376                 goto error;
 377         }
 378         if ((index_file = fopen(path, "r")) == NULL) {
 379                 err = Z_MISC_FS;
 380                 goto error;
 381         }
 382 
 383         exist = B_FALSE;
 384         zone_name = ze->zone_name;
 385         namelen = strlen(zone_name);
 386         zone_brand = ze->zone_brand;
 387         zone_iptype = (ze->zone_iptype == ZS_SHARED ? "sh" : "ex");
 388         zone_did = ze->zone_did;
 389         for (;;) {
 390                 if (fgets(buf, sizeof (buf), index_file) == NULL) {
 391                         if (operation == PZE_ADD && !exist) {
 392                                 zone_state = zone_state_str(ze->zone_state);
 393                                 zone_path = ze->zone_path;
 394                                 zone_uuid = "";
 395                                 goto add_entry;
 396                         }
 397                         /*
 398                          * It's not considered an error to delete something
 399                          * that doesn't exist, but we can't modify a missing
 400                          * record.
 401                          */
 402                         if (operation == PZE_MODIFY && !exist) {
 403                                 err = Z_UPDATING_INDEX;
 404                                 goto error;
 405                         }
 406                         break;
 407                 }
 408 


 423                         /* this represents a line that's too long; delete */
 424                         continue;
 425                 }
 426                 *cp = '\0';
 427 
 428                 /*
 429                  * Skip over the zone name.  Because we've already matched the
 430                  * target zone (above), we know for certain here that the zone
 431                  * name is present and correctly formed.  No need to check.
 432                  */
 433                 cp = strchr(buf, ':') + 1;
 434 
 435                 zone_state = gettok(&cp);
 436                 if (*zone_state == '\0') {
 437                         /* state field should not be empty */
 438                         err = Z_UPDATING_INDEX;
 439                         goto error;
 440                 }
 441                 zone_path = gettok(&cp);
 442                 zone_uuid = gettok(&cp);
 443                 zone_brand = gettok(&cp);
 444                 zone_iptype = gettok(&cp);
 445                 tmpp = gettok(&cp);
 446                 if (*tmpp != '\0')
 447                         zone_did = atoi(tmpp);
 448 
 449                 switch (operation) {
 450                 case PZE_ADD:
 451                         /* can't add same zone */
 452                         err = Z_UPDATING_INDEX;
 453                         goto error;
 454 
 455                 case PZE_MODIFY:
 456                         /*
 457                          * If the caller specified a new state for the zone,
 458                          * then use that.  Otherwise, use the current state.
 459                          */
 460                         if (ze->zone_state >= 0) {
 461                                 zone_state = zone_state_str(ze->zone_state);








 462                         }
 463 
 464                         /* If a new name is supplied, use it. */
 465                         if (ze->zone_newname[0] != '\0')
 466                                 zone_name = ze->zone_newname;
 467 
 468                         if (ze->zone_path[0] != '\0')
 469                                 zone_path = ze->zone_path;
 470 
 471                         /* If new UUID provided, replace it */
 472                         if (!uuid_is_null(ze->zone_uuid)) {
 473                                 uuid_unparse(ze->zone_uuid, uuidstr);
 474                                 zone_uuid = uuidstr;
 475                         }
 476 
 477                         /* If a brand is supplied, use it. */
 478                         if (ze->zone_brand[0] != '\0') {
 479                                 zone_brand = ze->zone_brand;
 480 
 481                                 /*
 482                                  * Since the brand, iptype and did are optional,
 483                                  * we we only reset the iptype and did if the
 484                                  * brand is provided.
 485                                  */
 486                                 zone_iptype = (ze->zone_iptype == ZS_SHARED ?
 487                                     "sh" : "ex");
 488                                 zone_did = ze->zone_did;
 489                         }
 490 
 491                         break;
 492 
 493                 case PZE_REMOVE:
 494                 default:
 495                         continue;
 496                 }
 497 
 498         add_entry:
 499                 /*
 500                  * If the entry in the file is in greater than configured
 501                  * state, then we must have a UUID.  Make sure that we do.
 502                  * (Note that the file entry is only tokenized, not fully
 503                  * parsed, so we need to do a string comparison here.)
 504                  */
 505                 if (strcmp(zone_state, ZONE_STATE_STR_CONFIGURED) != 0 &&
 506                     *zone_uuid == '\0') {
 507                         if (uuid_is_null(ze->zone_uuid))
 508                                 uuid_generate(ze->zone_uuid);
 509                         uuid_unparse(ze->zone_uuid, uuidstr);
 510                         zone_uuid = uuidstr;
 511                 }
 512                 /*
 513                  * We need to quote a path that contains a ":"; this should
 514                  * only affect the zonepath, as zone names do not allow such
 515                  * characters, and zone states do not have them either.  Same
 516                  * with double-quotes themselves: they are not allowed in zone
 517                  * names, and do not occur in zone states, and in theory should
 518                  * never occur in a zonepath since zonecfg does not support a
 519                  * method for escaping them.
 520                  */
 521                 need_quotes = (strchr(zone_path, ':') != NULL);
 522 
 523                 if (*zone_brand != '\0') {
 524                         (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s:%s:%s:%d\n",
 525                             zone_name, zone_state, need_quotes ? "\"" : "",
 526                             zone_path, need_quotes ? "\"" : "", zone_uuid,
 527                             zone_brand, zone_iptype, zone_did);
 528                 } else {
 529                         (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
 530                             zone_state, need_quotes ? "\"" : "", zone_path,
 531                             need_quotes ? "\"" : "", zone_uuid);
 532                 }
 533                 exist = B_TRUE;
 534         }
 535 
 536         (void) fclose(index_file);
 537         index_file = NULL;
 538         if (fclose(tmp_file) != 0) {
 539                 tmp_file = NULL;
 540                 err = Z_MISC_FS;
 541                 goto error;
 542         }
 543         tmp_file = NULL;
 544         if (rename(tmp_path, path) == -1) {
 545                 err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
 546                 goto error;
 547         }
 548         if (unlock_index_file(lock_fd) != Z_OK)
 549                 return (Z_UNLOCKING_FILE);
 550         return (Z_OK);
 551 
 552 error:


 111                 return (NULL);
 112 
 113         if ((ze = malloc(sizeof (struct zoneent))) == NULL)
 114                 return (NULL);
 115 
 116         for (;;) {
 117                 if (fgets(buf, sizeof (buf), cookie) == NULL) {
 118                         free(ze);
 119                         return (NULL);
 120                 }
 121                 if ((cp = strpbrk(buf, "\r\n")) == NULL) {
 122                         /* this represents a line that's too long */
 123                         continue;
 124                 }
 125                 *cp = '\0';
 126                 cp = buf;
 127                 if (*cp == '#') {
 128                         /* skip comment lines */
 129                         continue;
 130                 }


 131                 p = gettok(&cp);
 132                 if (*p == '\0' || strlen(p) >= ZONENAME_MAX) {
 133                         /*
 134                          * empty or very long zone names are not allowed
 135                          */
 136                         continue;
 137                 }
 138                 (void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
 139 

 140                 p = gettok(&cp);
 141                 if (*p == '\0') {
 142                         /* state field should not be empty */
 143                         continue;
 144                 }
 145                 errno = 0;
 146                 if (strcmp(p, ZONE_STATE_STR_CONFIGURED) == 0) {
 147                         ze->zone_state = ZONE_STATE_CONFIGURED;
 148                 } else if (strcmp(p, ZONE_STATE_STR_INCOMPLETE) == 0) {
 149                         ze->zone_state = ZONE_STATE_INCOMPLETE;
 150                 } else if (strcmp(p, ZONE_STATE_STR_INSTALLED) == 0) {
 151                         ze->zone_state = ZONE_STATE_INSTALLED;
 152                 } else {
 153                         continue;
 154                 }
 155 

 156                 p = gettok(&cp);
 157                 if (strlen(p) >= MAXPATHLEN) {
 158                         /* very long paths are not allowed */
 159                         continue;
 160                 }
 161                 (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
 162 

 163                 p = gettok(&cp);
 164                 if (uuid_parse(p, ze->zone_uuid) == -1)
 165                         uuid_clear(ze->zone_uuid);
 166 
























 167                 break;
 168         }
 169 
 170         return (ze);
 171 }
 172 
 173 static boolean_t
 174 path_common(char *path, size_t path_size, const char *stem)
 175 {
 176         const char *native_root = zone_get_nroot();
 177 
 178         if (native_root == NULL || zonecfg_in_alt_root()) {
 179                 /*
 180                  * Do not prepend the native system root (e.g. "/native") if an
 181                  * alternative configuration root has been selected.
 182                  */
 183                 native_root = "";
 184         }
 185 
 186         return (snprintf(path, path_size, "%s%s%s", native_root, zonecfg_root,


 277  *
 278  * A zero-length ze->zone_path means leave the existing value
 279  * unchanged; this is only meaningful when operation == PZE_MODIFY
 280  * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
 281  *
 282  * A zero-length ze->zone_newname means leave the existing name
 283  * unchanged; otherwise the zone is renamed to zone_newname.  This is
 284  * only meaningful when operation == PZE_MODIFY.
 285  *
 286  * Locking and unlocking is done via the functions above.
 287  * The file itself is not modified in place; rather, a copy is made which
 288  * is modified, then the copy is atomically renamed back to the main file.
 289  */
 290 int
 291 putzoneent(struct zoneent *ze, zoneent_op_t operation)
 292 {
 293         FILE *index_file, *tmp_file;
 294         char buf[MAX_INDEX_LEN];
 295         int tmp_file_desc, lock_fd, err;
 296         boolean_t exist, need_quotes;
 297         char *cp;
 298         char tmp_path[MAXPATHLEN];
 299         char path[MAXPATHLEN];
 300         char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
 301         size_t namelen;
 302         const char *zone_name, *zone_state, *zone_path, *zone_uuid;


 303 
 304         assert(ze != NULL);
 305 
 306         /*
 307          * Don't allow modification of Global Zone entry
 308          * in index file
 309          */
 310         if ((operation == PZE_MODIFY) &&
 311             (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
 312                 return (Z_OK);
 313         }
 314 
 315         if (operation == PZE_ADD &&
 316             (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
 317                 return (Z_INVAL);
 318 
 319         if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
 320                 return (Z_INVAL);
 321 
 322         if ((lock_fd = lock_index_file()) == -1)


 335         }
 336         (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
 337         (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
 338         if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
 339                 (void) close(tmp_file_desc);
 340                 err = Z_MISC_FS;
 341                 goto error;
 342         }
 343         if (!get_index_path(path, sizeof (path))) {
 344                 err = Z_MISC_FS;
 345                 goto error;
 346         }
 347         if ((index_file = fopen(path, "r")) == NULL) {
 348                 err = Z_MISC_FS;
 349                 goto error;
 350         }
 351 
 352         exist = B_FALSE;
 353         zone_name = ze->zone_name;
 354         namelen = strlen(zone_name);



 355         for (;;) {
 356                 if (fgets(buf, sizeof (buf), index_file) == NULL) {
 357                         if (operation == PZE_ADD && !exist) {
 358                                 zone_state = zone_state_str(ze->zone_state);
 359                                 zone_path = ze->zone_path;
 360                                 zone_uuid = "";
 361                                 goto add_entry;
 362                         }
 363                         /*
 364                          * It's not considered an error to delete something
 365                          * that doesn't exist, but we can't modify a missing
 366                          * record.
 367                          */
 368                         if (operation == PZE_MODIFY && !exist) {
 369                                 err = Z_UPDATING_INDEX;
 370                                 goto error;
 371                         }
 372                         break;
 373                 }
 374 


 389                         /* this represents a line that's too long; delete */
 390                         continue;
 391                 }
 392                 *cp = '\0';
 393 
 394                 /*
 395                  * Skip over the zone name.  Because we've already matched the
 396                  * target zone (above), we know for certain here that the zone
 397                  * name is present and correctly formed.  No need to check.
 398                  */
 399                 cp = strchr(buf, ':') + 1;
 400 
 401                 zone_state = gettok(&cp);
 402                 if (*zone_state == '\0') {
 403                         /* state field should not be empty */
 404                         err = Z_UPDATING_INDEX;
 405                         goto error;
 406                 }
 407                 zone_path = gettok(&cp);
 408                 zone_uuid = gettok(&cp);





 409 
 410                 switch (operation) {
 411                 case PZE_ADD:
 412                         /* can't add same zone */
 413                         err = Z_UPDATING_INDEX;
 414                         goto error;
 415 
 416                 case PZE_MODIFY:
 417                         /*
 418                          * If the caller specified a new state for the zone,
 419                          * then use that.  Otherwise, use the current state.
 420                          */
 421                         if (ze->zone_state >= 0) {
 422                                 zone_state = zone_state_str(ze->zone_state);
 423 
 424                                 /*
 425                                  * If the caller is uninstalling this zone,
 426                                  * then wipe out the uuid.  The zone's contents
 427                                  * are no longer known.
 428                                  */
 429                                 if (ze->zone_state < ZONE_STATE_INSTALLED)
 430                                         zone_uuid = "";
 431                         }
 432 
 433                         /* If a new name is supplied, use it. */
 434                         if (ze->zone_newname[0] != '\0')
 435                                 zone_name = ze->zone_newname;
 436 
 437                         if (ze->zone_path[0] != '\0')
 438                                 zone_path = ze->zone_path;





















 439                         break;
 440 
 441                 case PZE_REMOVE:
 442                 default:
 443                         continue;
 444                 }
 445 
 446         add_entry:
 447                 /*
 448                  * If the entry in the file is in greater than configured
 449                  * state, then we must have a UUID.  Make sure that we do.
 450                  * (Note that the file entry is only tokenized, not fully
 451                  * parsed, so we need to do a string comparison here.)
 452                  */
 453                 if (strcmp(zone_state, ZONE_STATE_STR_CONFIGURED) != 0 &&
 454                     *zone_uuid == '\0') {
 455                         if (uuid_is_null(ze->zone_uuid))
 456                                 uuid_generate(ze->zone_uuid);
 457                         uuid_unparse(ze->zone_uuid, uuidstr);
 458                         zone_uuid = uuidstr;
 459                 }
 460                 /*
 461                  * We need to quote a path that contains a ":"; this should
 462                  * only affect the zonepath, as zone names do not allow such
 463                  * characters, and zone states do not have them either.  Same
 464                  * with double-quotes themselves: they are not allowed in zone
 465                  * names, and do not occur in zone states, and in theory should
 466                  * never occur in a zonepath since zonecfg does not support a
 467                  * method for escaping them.
 468                  */
 469                 need_quotes = (strchr(zone_path, ':') != NULL);







 470                 (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
 471                     zone_state, need_quotes ? "\"" : "", zone_path,
 472                     need_quotes ? "\"" : "", zone_uuid);

 473                 exist = B_TRUE;
 474         }
 475 
 476         (void) fclose(index_file);
 477         index_file = NULL;
 478         if (fclose(tmp_file) != 0) {
 479                 tmp_file = NULL;
 480                 err = Z_MISC_FS;
 481                 goto error;
 482         }
 483         tmp_file = NULL;
 484         if (rename(tmp_path, path) == -1) {
 485                 err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
 486                 goto error;
 487         }
 488         if (unlock_index_file(lock_fd) != Z_OK)
 489                 return (Z_UNLOCKING_FILE);
 490         return (Z_OK);
 491 
 492 error: