Print this page
*** NO COMMENTS ***
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libbe/common/be_utils.c
+++ new/usr/src/lib/libbe/common/be_utils.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 - * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
27 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 28 */
29 29
30 30
31 31 /*
32 32 * System includes
33 33 */
34 34 #include <assert.h>
35 35 #include <errno.h>
36 36 #include <libgen.h>
37 37 #include <libintl.h>
38 38 #include <libnvpair.h>
39 39 #include <libzfs.h>
40 40 #include <libgen.h>
41 41 #include <stdio.h>
42 42 #include <stdlib.h>
43 43 #include <string.h>
44 44 #include <sys/stat.h>
45 45 #include <sys/types.h>
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
46 46 #include <sys/vfstab.h>
47 47 #include <sys/param.h>
48 48 #include <sys/systeminfo.h>
49 49 #include <ctype.h>
50 50 #include <time.h>
51 51 #include <unistd.h>
52 52 #include <fcntl.h>
53 53 #include <deflt.h>
54 54 #include <wait.h>
55 55 #include <libdevinfo.h>
56 +#include <libgen.h>
56 57
57 58 #include <libbe.h>
58 59 #include <libbe_priv.h>
59 60
60 61 /* Private function prototypes */
61 62 static int update_dataset(char *, int, char *, char *, char *);
62 63 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
63 64 static int be_open_menu(char *, char *, FILE **, char *, boolean_t);
64 65 static int be_create_menu(char *, char *, FILE **, char *);
65 66 static char *be_get_auto_name(char *, char *, boolean_t);
66 67
67 68 /*
68 69 * Global error printing
69 70 */
70 71 boolean_t do_print = B_FALSE;
71 72
72 73 /*
73 74 * Private datatypes
74 75 */
75 76 typedef struct zone_be_name_cb_data {
76 77 char *base_be_name;
77 78 int num;
78 79 } zone_be_name_cb_data_t;
79 80
80 81 /* ******************************************************************** */
81 82 /* Public Functions */
82 83 /* ******************************************************************** */
83 84
84 85 /*
85 86 * Function: be_max_avail
86 87 * Description: Returns the available size for the zfs dataset passed in.
87 88 * Parameters:
88 89 * dataset - The dataset we want to get the available space for.
89 90 * ret - The available size will be returned in this.
90 91 * Returns:
91 92 * The error returned by the zfs get property function.
92 93 * Scope:
93 94 * Public
94 95 */
95 96 int
96 97 be_max_avail(char *dataset, uint64_t *ret)
97 98 {
98 99 zfs_handle_t *zhp;
99 100 int err = 0;
100 101
101 102 /* Initialize libzfs handle */
102 103 if (!be_zfs_init())
103 104 return (BE_ERR_INIT);
104 105
105 106 zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
106 107 if (zhp == NULL) {
107 108 /*
108 109 * The zfs_open failed return an error
109 110 */
110 111 err = zfs_err_to_be_err(g_zfs);
111 112 } else {
112 113 err = be_maxsize_avail(zhp, ret);
113 114 }
114 115 ZFS_CLOSE(zhp);
115 116 be_zfs_fini();
116 117 return (err);
117 118 }
118 119
119 120 /*
120 121 * Function: libbe_print_errors
121 122 * Description: Turns on/off error output for the library.
122 123 * Parameter:
123 124 * set_do_print - Boolean that turns library error
124 125 * printing on or off.
125 126 * Returns:
126 127 * None
127 128 * Scope:
128 129 * Public;
129 130 */
130 131 void
131 132 libbe_print_errors(boolean_t set_do_print)
132 133 {
133 134 do_print = set_do_print;
134 135 }
135 136
136 137 /* ******************************************************************** */
137 138 /* Semi-Private Functions */
138 139 /* ******************************************************************** */
139 140
140 141 /*
141 142 * Function: be_zfs_init
142 143 * Description: Initializes the libary global libzfs handle.
143 144 * Parameters:
144 145 * None
145 146 * Returns:
146 147 * B_TRUE - Success
147 148 * B_FALSE - Failure
148 149 * Scope:
149 150 * Semi-private (library wide use only)
150 151 */
151 152 boolean_t
152 153 be_zfs_init(void)
153 154 {
154 155 be_zfs_fini();
155 156
156 157 if ((g_zfs = libzfs_init()) == NULL) {
157 158 be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
158 159 "library\n"));
159 160 return (B_FALSE);
160 161 }
161 162
162 163 return (B_TRUE);
163 164 }
164 165
165 166 /*
166 167 * Function: be_zfs_fini
167 168 * Description: Closes the library global libzfs handle if it currently open.
168 169 * Parameter:
169 170 * None
170 171 * Returns:
171 172 * None
172 173 * Scope:
173 174 * Semi-private (library wide use only)
174 175 */
175 176 void
176 177 be_zfs_fini(void)
177 178 {
178 179 if (g_zfs)
179 180 libzfs_fini(g_zfs);
180 181
181 182 g_zfs = NULL;
182 183 }
183 184
184 185 /*
185 186 * Function: be_get_defaults
186 187 * Description: Open defaults and gets be default paramets
187 188 * Parameters:
188 189 * defaults - be defaults struct
189 190 * Returns:
190 191 * None
191 192 * Scope:
192 193 * Semi-private (library wide use only)
193 194 */
194 195 void
195 196 be_get_defaults(struct be_defaults *defaults)
196 197 {
197 198 void *defp;
198 199
199 200 defaults->be_deflt_rpool_container = B_FALSE;
200 201 defaults->be_deflt_bename_starts_with[0] = '\0';
201 202
202 203 if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
203 204 const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp);
204 205 if (res != NULL && res[0] != NULL) {
205 206 (void) strlcpy(defaults->be_deflt_bename_starts_with,
206 207 res, ZFS_MAXNAMELEN);
207 208 defaults->be_deflt_rpool_container = B_TRUE;
208 209 }
209 210 defclose_r(defp);
210 211 }
211 212 }
212 213
213 214 /*
214 215 * Function: be_make_root_ds
215 216 * Description: Generate string for BE's root dataset given the pool
216 217 * it lives in and the BE name.
217 218 * Parameters:
218 219 * zpool - pointer zpool name.
219 220 * be_name - pointer to BE name.
220 221 * be_root_ds - pointer to buffer to return BE root dataset in.
221 222 * be_root_ds_size - size of be_root_ds
222 223 * Returns:
↓ open down ↓ |
157 lines elided |
↑ open up ↑ |
223 224 * None
224 225 * Scope:
225 226 * Semi-private (library wide use only)
226 227 */
227 228 void
228 229 be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
229 230 int be_root_ds_size)
230 231 {
231 232 struct be_defaults be_defaults;
232 233 be_get_defaults(&be_defaults);
234 + char *root_ds = NULL;
233 235
234 - if (be_defaults.be_deflt_rpool_container)
235 - (void) snprintf(be_root_ds, be_root_ds_size, "%s/%s", zpool,
236 - be_name);
237 - else
238 - (void) snprintf(be_root_ds, be_root_ds_size, "%s/%s/%s", zpool,
239 - BE_CONTAINER_DS_NAME, be_name);
236 + if (getzoneid() == GLOBAL_ZONEID) {
237 + if (be_defaults.be_deflt_rpool_container) {
238 + (void) snprintf(be_root_ds, be_root_ds_size,
239 + "%s/%s", zpool, be_name);
240 + } else {
241 + (void) snprintf(be_root_ds, be_root_ds_size,
242 + "%s/%s/%s", zpool, BE_CONTAINER_DS_NAME, be_name);
243 + }
244 + } else {
245 + /*
246 + * In non-global zone we can use path from mounted root dataset
247 + * to generate BE's root dataset string.
248 + */
249 + if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
250 + (void) snprintf(be_root_ds, be_root_ds_size, "%s/%s",
251 + dirname(root_ds), be_name);
252 + } else {
253 + be_print_err(gettext("be_make_root_ds: zone root "
254 + "dataset is not mounted\n"));
255 + return;
256 + }
257 + }
240 258 }
241 259
242 260 /*
243 261 * Function: be_make_container_ds
244 262 * Description: Generate string for the BE container dataset given a pool name.
245 263 * Parameters:
246 264 * zpool - pointer zpool name.
247 265 * container_ds - pointer to buffer to return BE container
248 266 * dataset in.
249 267 * container_ds_size - size of container_ds
250 268 * Returns:
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
251 269 * None
252 270 * Scope:
253 271 * Semi-private (library wide use only)
254 272 */
255 273 void
256 274 be_make_container_ds(const char *zpool, char *container_ds,
257 275 int container_ds_size)
258 276 {
259 277 struct be_defaults be_defaults;
260 278 be_get_defaults(&be_defaults);
279 + char *root_ds = NULL;
261 280
262 - if (be_defaults.be_deflt_rpool_container)
263 - (void) snprintf(container_ds, container_ds_size, "%s", zpool);
264 - else
265 - (void) snprintf(container_ds, container_ds_size, "%s/%s", zpool,
266 - BE_CONTAINER_DS_NAME);
281 + if (getzoneid() == GLOBAL_ZONEID) {
282 + if (be_defaults.be_deflt_rpool_container) {
283 + (void) snprintf(container_ds, container_ds_size,
284 + "%s", zpool);
285 + } else {
286 + (void) snprintf(container_ds, container_ds_size,
287 + "%s/%s", zpool, BE_CONTAINER_DS_NAME);
288 + }
289 + } else {
290 + if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
291 + (void) strlcpy(container_ds, dirname(root_ds),
292 + container_ds_size);
293 + } else {
294 + be_print_err(gettext("be_make_container_ds: zone root "
295 + "dataset is not mounted\n"));
296 + return;
297 + }
298 + }
267 299 }
268 300
269 301 /*
270 302 * Function: be_make_name_from_ds
271 303 * Description: This function takes a dataset name and strips off the
272 304 * BE container dataset portion from the beginning. The
273 305 * returned name is allocated in heap storage, so the caller
274 306 * is responsible for freeing it.
275 307 * Parameters:
276 308 * dataset - dataset to get name from.
277 309 * rc_loc - dataset underwhich the root container dataset lives.
278 310 * Returns:
279 311 * name of dataset relative to BE container dataset.
280 312 * NULL if dataset is not under a BE root dataset.
281 313 * Scope:
282 314 * Semi-primate (library wide use only)
283 315 */
284 316 char *
285 317 be_make_name_from_ds(const char *dataset, char *rc_loc)
286 318 {
287 319 char ds[ZFS_MAXNAMELEN];
288 320 char *tok = NULL;
289 321 char *name = NULL;
290 322 struct be_defaults be_defaults;
291 323 int rlen = strlen(rc_loc);
292 324
293 325 be_get_defaults(&be_defaults);
294 326
295 327 /*
296 328 * First token is the location of where the root container dataset
297 329 * lives; it must match rc_loc.
298 330 */
299 331 if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/')
300 332 (void) strlcpy(ds, dataset + rlen + 1, sizeof (ds));
301 333 else
302 334 return (NULL);
303 335
304 336 if (be_defaults.be_deflt_rpool_container) {
305 337 if ((name = strdup(ds)) == NULL) {
306 338 be_print_err(gettext("be_make_name_from_ds: "
307 339 "memory allocation failed\n"));
308 340 return (NULL);
309 341 }
310 342 } else {
311 343 /* Second token must be BE container dataset name */
312 344 if ((tok = strtok(ds, "/")) == NULL ||
313 345 strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
314 346 return (NULL);
315 347
316 348 /* Return the remaining token if one exists */
317 349 if ((tok = strtok(NULL, "")) == NULL)
318 350 return (NULL);
319 351
320 352 if ((name = strdup(tok)) == NULL) {
321 353 be_print_err(gettext("be_make_name_from_ds: "
322 354 "memory allocation failed\n"));
323 355 return (NULL);
324 356 }
325 357 }
326 358
327 359 return (name);
328 360 }
329 361
330 362 /*
331 363 * Function: be_maxsize_avail
332 364 * Description: Returns the available size for the zfs handle passed in.
333 365 * Parameters:
334 366 * zhp - A pointer to the open zfs handle.
335 367 * ret - The available size will be returned in this.
336 368 * Returns:
337 369 * The error returned by the zfs get property function.
338 370 * Scope:
339 371 * Semi-private (library wide use only)
340 372 */
341 373 int
342 374 be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
343 375 {
344 376 return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
345 377 }
346 378
347 379 /*
348 380 * Function: be_append_menu
349 381 * Description: Appends an entry for a BE into the menu.lst.
350 382 * Parameters:
351 383 * be_name - pointer to name of BE to add boot menu entry for.
352 384 * be_root_pool - pointer to name of pool BE lives in.
353 385 * boot_pool - Used if the pool containing the grub menu is
354 386 * different than the one contaiing the BE. This
355 387 * will normally be NULL.
356 388 * be_orig_root_ds - The root dataset for the BE. This is
357 389 * used to check to see if an entry already exists
358 390 * for this BE.
359 391 * description - pointer to description of BE to be added in
360 392 * the title line for this BEs entry.
361 393 * Returns:
362 394 * BE_SUCCESS - Success
363 395 * be_errno_t - Failure
364 396 * Scope:
365 397 * Semi-private (library wide use only)
366 398 */
367 399 int
368 400 be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
369 401 char *be_orig_root_ds, char *description)
370 402 {
371 403 zfs_handle_t *zhp = NULL;
372 404 char menu_file[MAXPATHLEN];
373 405 char be_root_ds[MAXPATHLEN];
374 406 char line[BUFSIZ];
375 407 char temp_line[BUFSIZ];
376 408 char title[MAXPATHLEN];
377 409 char *entries[BUFSIZ];
378 410 char *tmp_entries[BUFSIZ];
379 411 char *pool_mntpnt = NULL;
380 412 char *ptmp_mntpnt = NULL;
381 413 char *orig_mntpnt = NULL;
382 414 boolean_t found_be = B_FALSE;
383 415 boolean_t found_orig_be = B_FALSE;
384 416 boolean_t found_title = B_FALSE;
385 417 boolean_t pool_mounted = B_FALSE;
386 418 boolean_t collect_lines = B_FALSE;
387 419 FILE *menu_fp = NULL;
388 420 int err = 0, ret = BE_SUCCESS;
389 421 int i, num_tmp_lines = 0, num_lines = 0;
390 422
391 423 if (be_name == NULL || be_root_pool == NULL)
392 424 return (BE_ERR_INVAL);
393 425
394 426 if (boot_pool == NULL)
395 427 boot_pool = be_root_pool;
396 428
397 429 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
398 430 be_print_err(gettext("be_append_menu: failed to open "
399 431 "pool dataset for %s: %s\n"), be_root_pool,
400 432 libzfs_error_description(g_zfs));
401 433 return (zfs_err_to_be_err(g_zfs));
402 434 }
403 435
404 436 /*
405 437 * Check to see if the pool's dataset is mounted. If it isn't we'll
406 438 * attempt to mount it.
407 439 */
408 440 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
409 441 &pool_mounted)) != BE_SUCCESS) {
410 442 be_print_err(gettext("be_append_menu: pool dataset "
411 443 "(%s) could not be mounted\n"), be_root_pool);
412 444 ZFS_CLOSE(zhp);
413 445 return (ret);
414 446 }
415 447
416 448 /*
417 449 * Get the mountpoint for the root pool dataset.
418 450 */
419 451 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
420 452 be_print_err(gettext("be_append_menu: pool "
421 453 "dataset (%s) is not mounted. Can't set "
422 454 "the default BE in the grub menu.\n"), be_root_pool);
423 455 ret = BE_ERR_NO_MENU;
424 456 goto cleanup;
425 457 }
426 458
427 459 /*
428 460 * Check to see if this system supports grub
429 461 */
430 462 if (be_has_grub()) {
431 463 (void) snprintf(menu_file, sizeof (menu_file),
432 464 "%s%s", pool_mntpnt, BE_GRUB_MENU);
433 465 } else {
434 466 (void) snprintf(menu_file, sizeof (menu_file),
435 467 "%s%s", pool_mntpnt, BE_SPARC_MENU);
436 468 }
437 469
438 470 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
439 471
440 472 /*
441 473 * Iterate through menu first to make sure the BE doesn't already
442 474 * have an entry in the menu.
443 475 *
444 476 * Additionally while iterating through the menu, if we have an
445 477 * original root dataset for a BE we're cloning from, we need to keep
446 478 * track of that BE's menu entry. We will then use the lines from
447 479 * that entry to create the entry for the new BE.
448 480 */
449 481 if ((ret = be_open_menu(be_root_pool, menu_file,
450 482 &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
451 483 goto cleanup;
452 484 } else if (menu_fp == NULL) {
453 485 ret = BE_ERR_NO_MENU;
454 486 goto cleanup;
455 487 }
456 488
457 489 free(pool_mntpnt);
458 490 pool_mntpnt = NULL;
459 491
460 492 while (fgets(line, BUFSIZ, menu_fp)) {
461 493 char *tok = NULL;
462 494
463 495 (void) strlcpy(temp_line, line, BUFSIZ);
464 496 tok = strtok(line, BE_WHITE_SPACE);
465 497
466 498 if (tok == NULL || tok[0] == '#') {
467 499 continue;
468 500 } else if (strcmp(tok, "title") == 0) {
469 501 collect_lines = B_FALSE;
470 502 if ((tok = strtok(NULL, "\n")) == NULL)
471 503 (void) strlcpy(title, "", sizeof (title));
472 504 else
473 505 (void) strlcpy(title, tok, sizeof (title));
474 506 found_title = B_TRUE;
475 507
476 508 if (num_tmp_lines != 0) {
477 509 for (i = 0; i < num_tmp_lines; i++) {
478 510 free(tmp_entries[i]);
479 511 tmp_entries[i] = NULL;
480 512 }
481 513 num_tmp_lines = 0;
482 514 }
483 515 } else if (strcmp(tok, "bootfs") == 0) {
484 516 char *bootfs = strtok(NULL, BE_WHITE_SPACE);
485 517 found_title = B_FALSE;
486 518 if (bootfs == NULL)
487 519 continue;
488 520
489 521 if (strcmp(bootfs, be_root_ds) == 0) {
490 522 found_be = B_TRUE;
491 523 break;
492 524 }
493 525
494 526 if (be_orig_root_ds != NULL &&
495 527 strcmp(bootfs, be_orig_root_ds) == 0 &&
496 528 !found_orig_be) {
497 529 char str[BUFSIZ];
498 530 found_orig_be = B_TRUE;
499 531 num_lines = 0;
500 532 /*
501 533 * Store the new title line
502 534 */
503 535 (void) snprintf(str, BUFSIZ, "title %s\n",
504 536 description ? description : be_name);
505 537 entries[num_lines] = strdup(str);
506 538 num_lines++;
507 539 /*
508 540 * If there are any lines between the title
509 541 * and the bootfs line store these. Also
510 542 * free the temporary lines.
511 543 */
512 544 for (i = 0; i < num_tmp_lines; i++) {
513 545 entries[num_lines] = tmp_entries[i];
514 546 tmp_entries[i] = NULL;
515 547 num_lines++;
516 548 }
517 549 num_tmp_lines = 0;
518 550 /*
519 551 * Store the new bootfs line.
520 552 */
521 553 (void) snprintf(str, BUFSIZ, "bootfs %s\n",
522 554 be_root_ds);
523 555 entries[num_lines] = strdup(str);
524 556 num_lines++;
525 557 collect_lines = B_TRUE;
526 558 }
527 559 } else if (found_orig_be && collect_lines) {
528 560 /*
529 561 * get the rest of the lines for the original BE and
530 562 * store them.
531 563 */
532 564 if (strstr(line, BE_GRUB_COMMENT) != NULL ||
533 565 strstr(line, "BOOTADM") != NULL)
534 566 continue;
535 567 if (strcmp(tok, "splashimage") == 0) {
536 568 entries[num_lines] =
537 569 strdup("splashimage "
538 570 "/boot/splashimage.xpm\n");
539 571 } else {
540 572 entries[num_lines] = strdup(temp_line);
541 573 }
542 574 num_lines++;
543 575 } else if (found_title && !found_orig_be) {
544 576 tmp_entries[num_tmp_lines] = strdup(temp_line);
545 577 num_tmp_lines++;
546 578 }
547 579 }
548 580
549 581 (void) fclose(menu_fp);
550 582
551 583 if (found_be) {
552 584 /*
553 585 * If an entry for this BE was already in the menu, then if
554 586 * that entry's title matches what we would have put in
555 587 * return success. Otherwise return failure.
556 588 */
557 589 char *new_title = description ? description : be_name;
558 590
559 591 if (strcmp(title, new_title) == 0) {
560 592 ret = BE_SUCCESS;
561 593 goto cleanup;
562 594 } else {
563 595 if (be_remove_menu(be_name, be_root_pool,
564 596 boot_pool) != BE_SUCCESS) {
565 597 be_print_err(gettext("be_append_menu: "
566 598 "Failed to remove existing unusable "
567 599 "entry '%s' in boot menu.\n"), be_name);
568 600 ret = BE_ERR_BE_EXISTS;
569 601 goto cleanup;
570 602 }
571 603 }
572 604 }
573 605
574 606 /* Append BE entry to the end of the file */
575 607 menu_fp = fopen(menu_file, "a+");
576 608 err = errno;
577 609 if (menu_fp == NULL) {
578 610 be_print_err(gettext("be_append_menu: failed "
579 611 "to open menu.lst file %s\n"), menu_file);
580 612 ret = errno_to_be_err(err);
581 613 goto cleanup;
582 614 }
583 615
584 616 if (found_orig_be) {
585 617 /*
586 618 * write out all the stored lines
587 619 */
588 620 for (i = 0; i < num_lines; i++) {
589 621 (void) fprintf(menu_fp, "%s", entries[i]);
590 622 free(entries[i]);
591 623 }
592 624 num_lines = 0;
593 625
594 626 /*
595 627 * Check to see if this system supports grub
596 628 */
597 629 if (be_has_grub())
598 630 (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
599 631 ret = BE_SUCCESS;
600 632 } else {
601 633 (void) fprintf(menu_fp, "title %s\n",
602 634 description ? description : be_name);
603 635 (void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
604 636
605 637 /*
606 638 * Check to see if this system supports grub
607 639 */
608 640 if (be_has_grub()) {
609 641 (void) fprintf(menu_fp, "kernel$ "
610 642 "/platform/i86pc/kernel/$ISADIR/unix -B "
611 643 "$ZFS-BOOTFS\n");
612 644 (void) fprintf(menu_fp, "module$ "
613 645 "/platform/i86pc/$ISADIR/boot_archive\n");
614 646 (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
615 647 }
616 648 ret = BE_SUCCESS;
617 649 }
618 650 (void) fclose(menu_fp);
619 651 cleanup:
620 652 if (pool_mounted) {
621 653 int err = BE_SUCCESS;
622 654 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
623 655 if (ret == BE_SUCCESS)
624 656 ret = err;
625 657 free(orig_mntpnt);
626 658 free(ptmp_mntpnt);
627 659 }
628 660 ZFS_CLOSE(zhp);
629 661 if (num_tmp_lines > 0) {
630 662 for (i = 0; i < num_tmp_lines; i++) {
631 663 free(tmp_entries[i]);
632 664 tmp_entries[i] = NULL;
633 665 }
634 666 }
635 667 if (num_lines > 0) {
636 668 for (i = 0; i < num_lines; i++) {
637 669 free(entries[i]);
638 670 entries[i] = NULL;
639 671 }
640 672 }
641 673 return (ret);
642 674 }
643 675
644 676 /*
645 677 * Function: be_remove_menu
646 678 * Description: Removes a BE's entry from a menu.lst file.
647 679 * Parameters:
648 680 * be_name - the name of BE whose entry is to be removed from
649 681 * the menu.lst file.
650 682 * be_root_pool - the pool that be_name lives in.
651 683 * boot_pool - the pool where the BE is, if different than
652 684 * the pool containing the boot menu. If this is
653 685 * NULL it will be set to be_root_pool.
654 686 * Returns:
655 687 * BE_SUCCESS - Success
656 688 * be_errno_t - Failure
657 689 * Scope:
658 690 * Semi-private (library wide use only)
659 691 */
660 692 int
661 693 be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool)
662 694 {
663 695 zfs_handle_t *zhp = NULL;
664 696 char be_root_ds[MAXPATHLEN];
665 697 char **buffer = NULL;
666 698 char menu_buf[BUFSIZ];
667 699 char menu[MAXPATHLEN];
668 700 char *pool_mntpnt = NULL;
669 701 char *ptmp_mntpnt = NULL;
670 702 char *orig_mntpnt = NULL;
671 703 char *tmp_menu = NULL;
672 704 FILE *menu_fp = NULL;
673 705 FILE *tmp_menu_fp = NULL;
674 706 struct stat sb;
675 707 int ret = BE_SUCCESS;
676 708 int i;
677 709 int fd;
678 710 int err = 0;
679 711 int nlines = 0;
680 712 int default_entry = 0;
681 713 int entry_cnt = 0;
682 714 int entry_del = 0;
683 715 int num_entry_del = 0;
684 716 int tmp_menu_len = 0;
685 717 boolean_t write = B_TRUE;
686 718 boolean_t do_buffer = B_FALSE;
687 719 boolean_t pool_mounted = B_FALSE;
688 720
689 721 if (boot_pool == NULL)
690 722 boot_pool = be_root_pool;
691 723
692 724 /* Get name of BE's root dataset */
693 725 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
694 726
695 727 /* Get handle to pool dataset */
696 728 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
697 729 be_print_err(gettext("be_remove_menu: "
698 730 "failed to open pool dataset for %s: %s"),
699 731 be_root_pool, libzfs_error_description(g_zfs));
700 732 return (zfs_err_to_be_err(g_zfs));
701 733 }
702 734
703 735 /*
704 736 * Check to see if the pool's dataset is mounted. If it isn't we'll
705 737 * attempt to mount it.
706 738 */
707 739 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
708 740 &pool_mounted)) != BE_SUCCESS) {
709 741 be_print_err(gettext("be_remove_menu: pool dataset "
710 742 "(%s) could not be mounted\n"), be_root_pool);
711 743 ZFS_CLOSE(zhp);
712 744 return (ret);
713 745 }
714 746
715 747 /*
716 748 * Get the mountpoint for the root pool dataset.
717 749 */
718 750 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
719 751 be_print_err(gettext("be_remove_menu: pool "
720 752 "dataset (%s) is not mounted. Can't set "
721 753 "the default BE in the grub menu.\n"), be_root_pool);
722 754 ret = BE_ERR_NO_MENU;
723 755 goto cleanup;
724 756 }
725 757
726 758 /* Get path to boot menu */
727 759 (void) strlcpy(menu, pool_mntpnt, sizeof (menu));
728 760
729 761 /*
730 762 * Check to see if this system supports grub
731 763 */
732 764 if (be_has_grub())
733 765 (void) strlcat(menu, BE_GRUB_MENU, sizeof (menu));
734 766 else
735 767 (void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
736 768
737 769 /* Get handle to boot menu file */
738 770 if ((ret = be_open_menu(be_root_pool, menu, &menu_fp, "r",
739 771 B_TRUE)) != BE_SUCCESS) {
740 772 goto cleanup;
741 773 } else if (menu_fp == NULL) {
742 774 ret = BE_ERR_NO_MENU;
743 775 goto cleanup;
744 776 }
745 777
746 778 free(pool_mntpnt);
747 779 pool_mntpnt = NULL;
748 780
749 781 /* Grab the stats of the original menu file */
750 782 if (stat(menu, &sb) != 0) {
751 783 err = errno;
752 784 be_print_err(gettext("be_remove_menu: "
753 785 "failed to stat file %s: %s\n"), menu, strerror(err));
754 786 ret = errno_to_be_err(err);
755 787 goto cleanup;
756 788 }
757 789
758 790 /* Create a tmp file for the modified menu.lst */
759 791 tmp_menu_len = strlen(menu) + 7;
760 792 if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) {
761 793 be_print_err(gettext("be_remove_menu: malloc failed\n"));
762 794 ret = BE_ERR_NOMEM;
763 795 goto cleanup;
764 796 }
765 797 (void) memset(tmp_menu, 0, tmp_menu_len);
766 798 (void) strlcpy(tmp_menu, menu, tmp_menu_len);
767 799 (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
768 800 if ((fd = mkstemp(tmp_menu)) == -1) {
769 801 err = errno;
770 802 be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
771 803 ret = errno_to_be_err(err);
772 804 free(tmp_menu);
773 805 tmp_menu = NULL;
774 806 goto cleanup;
775 807 }
776 808 if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
777 809 err = errno;
778 810 be_print_err(gettext("be_remove_menu: "
779 811 "could not open tmp file for write: %s\n"), strerror(err));
780 812 (void) close(fd);
781 813 ret = errno_to_be_err(err);
782 814 goto cleanup;
783 815 }
784 816
785 817 while (fgets(menu_buf, BUFSIZ, menu_fp)) {
786 818 char tline [BUFSIZ];
787 819 char *tok = NULL;
788 820
789 821 (void) strlcpy(tline, menu_buf, sizeof (tline));
790 822
791 823 /* Tokenize line */
792 824 tok = strtok(tline, BE_WHITE_SPACE);
793 825
794 826 if (tok == NULL || tok[0] == '#') {
795 827 /* Found empty line or comment line */
796 828 if (do_buffer) {
797 829 /* Buffer this line */
798 830 if ((buffer = (char **)realloc(buffer,
799 831 sizeof (char *)*(nlines + 1))) == NULL) {
800 832 ret = BE_ERR_NOMEM;
801 833 goto cleanup;
802 834 }
803 835 if ((buffer[nlines++] = strdup(menu_buf))
804 836 == NULL) {
805 837 ret = BE_ERR_NOMEM;
806 838 goto cleanup;
807 839 }
808 840
809 841 } else if (write || strncmp(menu_buf, BE_GRUB_COMMENT,
810 842 strlen(BE_GRUB_COMMENT)) != 0) {
811 843 /* Write this line out */
812 844 (void) fputs(menu_buf, tmp_menu_fp);
813 845 }
814 846 } else if (strcmp(tok, "default") == 0) {
815 847 /*
816 848 * Record what 'default' is set to because we might
817 849 * need to adjust this upon deleting an entry.
818 850 */
819 851 tok = strtok(NULL, BE_WHITE_SPACE);
820 852
821 853 if (tok != NULL) {
822 854 default_entry = atoi(tok);
823 855 }
824 856
825 857 (void) fputs(menu_buf, tmp_menu_fp);
826 858 } else if (strcmp(tok, "title") == 0) {
827 859 /*
828 860 * If we've reached a 'title' line and do_buffer is
829 861 * is true, that means we've just buffered an entire
830 862 * entry without finding a 'bootfs' directive. We
831 863 * need to write that entry out and keep searching.
832 864 */
833 865 if (do_buffer) {
834 866 for (i = 0; i < nlines; i++) {
835 867 (void) fputs(buffer[i], tmp_menu_fp);
836 868 free(buffer[i]);
837 869 }
838 870 free(buffer);
839 871 buffer = NULL;
840 872 nlines = 0;
841 873 }
842 874
843 875 /*
844 876 * Turn writing off and buffering on, and increment
845 877 * our entry counter.
846 878 */
847 879 write = B_FALSE;
848 880 do_buffer = B_TRUE;
849 881 entry_cnt++;
850 882
851 883 /* Buffer this 'title' line */
852 884 if ((buffer = (char **)realloc(buffer,
853 885 sizeof (char *)*(nlines + 1))) == NULL) {
854 886 ret = BE_ERR_NOMEM;
855 887 goto cleanup;
856 888 }
857 889 if ((buffer[nlines++] = strdup(menu_buf)) == NULL) {
858 890 ret = BE_ERR_NOMEM;
859 891 goto cleanup;
860 892 }
861 893
862 894 } else if (strcmp(tok, "bootfs") == 0) {
863 895 char *bootfs = NULL;
864 896
865 897 /*
866 898 * Found a 'bootfs' line. See if it matches the
867 899 * BE we're looking for.
868 900 */
869 901 if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL ||
870 902 strcmp(bootfs, be_root_ds) != 0) {
871 903 /*
872 904 * Either there's nothing after the 'bootfs'
873 905 * or this is not the BE we're looking for,
874 906 * write out the line(s) we've buffered since
875 907 * finding the title.
876 908 */
877 909 for (i = 0; i < nlines; i++) {
878 910 (void) fputs(buffer[i], tmp_menu_fp);
879 911 free(buffer[i]);
880 912 }
881 913 free(buffer);
882 914 buffer = NULL;
883 915 nlines = 0;
884 916
885 917 /*
886 918 * Turn writing back on, and turn off buffering
887 919 * since this isn't the entry we're looking
888 920 * for.
889 921 */
890 922 write = B_TRUE;
891 923 do_buffer = B_FALSE;
892 924
893 925 /* Write this 'bootfs' line out. */
894 926 (void) fputs(menu_buf, tmp_menu_fp);
895 927 } else {
896 928 /*
897 929 * Found the entry we're looking for.
898 930 * Record its entry number, increment the
899 931 * number of entries we've deleted, and turn
900 932 * writing off. Also, throw away the lines
901 933 * we've buffered for this entry so far, we
902 934 * don't need them.
903 935 */
904 936 entry_del = entry_cnt - 1;
905 937 num_entry_del++;
906 938 write = B_FALSE;
907 939 do_buffer = B_FALSE;
908 940
909 941 for (i = 0; i < nlines; i++) {
910 942 free(buffer[i]);
911 943 }
912 944 free(buffer);
913 945 buffer = NULL;
914 946 nlines = 0;
915 947 }
916 948 } else {
917 949 if (do_buffer) {
918 950 /* Buffer this line */
919 951 if ((buffer = (char **)realloc(buffer,
920 952 sizeof (char *)*(nlines + 1))) == NULL) {
921 953 ret = BE_ERR_NOMEM;
922 954 goto cleanup;
923 955 }
924 956 if ((buffer[nlines++] = strdup(menu_buf))
925 957 == NULL) {
926 958 ret = BE_ERR_NOMEM;
927 959 goto cleanup;
928 960 }
929 961 } else if (write) {
930 962 /* Write this line out */
931 963 (void) fputs(menu_buf, tmp_menu_fp);
932 964 }
933 965 }
934 966 }
935 967
936 968 (void) fclose(menu_fp);
937 969 menu_fp = NULL;
938 970 (void) fclose(tmp_menu_fp);
939 971 tmp_menu_fp = NULL;
940 972
941 973 /* Copy the modified menu.lst into place */
942 974 if (rename(tmp_menu, menu) != 0) {
943 975 err = errno;
944 976 be_print_err(gettext("be_remove_menu: "
945 977 "failed to rename file %s to %s: %s\n"),
946 978 tmp_menu, menu, strerror(err));
947 979 ret = errno_to_be_err(err);
948 980 goto cleanup;
949 981 }
950 982 free(tmp_menu);
951 983 tmp_menu = NULL;
952 984
953 985 /*
954 986 * If we've removed an entry, see if we need to
955 987 * adjust the default value in the menu.lst. If the
956 988 * entry we've deleted comes before the default entry
957 989 * we need to adjust the default value accordingly.
958 990 *
959 991 * be_has_grub is used here to check to see if this system
960 992 * supports grub.
961 993 */
962 994 if (be_has_grub() && num_entry_del > 0) {
963 995 if (entry_del <= default_entry) {
964 996 default_entry = default_entry - num_entry_del;
965 997 if (default_entry < 0)
966 998 default_entry = 0;
967 999
968 1000 /*
969 1001 * Adjust the default value by rewriting the
970 1002 * menu.lst file. This may be overkill, but to
971 1003 * preserve the location of the 'default' entry
972 1004 * in the file, we need to do this.
973 1005 */
974 1006
975 1007 /* Get handle to boot menu file */
976 1008 if ((menu_fp = fopen(menu, "r")) == NULL) {
977 1009 err = errno;
978 1010 be_print_err(gettext("be_remove_menu: "
979 1011 "failed to open menu.lst (%s): %s\n"),
980 1012 menu, strerror(err));
981 1013 ret = errno_to_be_err(err);
982 1014 goto cleanup;
983 1015 }
984 1016
985 1017 /* Create a tmp file for the modified menu.lst */
986 1018 tmp_menu_len = strlen(menu) + 7;
987 1019 if ((tmp_menu = (char *)malloc(tmp_menu_len))
988 1020 == NULL) {
989 1021 be_print_err(gettext("be_remove_menu: "
990 1022 "malloc failed\n"));
991 1023 ret = BE_ERR_NOMEM;
992 1024 goto cleanup;
993 1025 }
994 1026 (void) memset(tmp_menu, 0, tmp_menu_len);
995 1027 (void) strlcpy(tmp_menu, menu, tmp_menu_len);
996 1028 (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
997 1029 if ((fd = mkstemp(tmp_menu)) == -1) {
998 1030 err = errno;
999 1031 be_print_err(gettext("be_remove_menu: "
1000 1032 "mkstemp failed: %s\n"), strerror(err));
1001 1033 ret = errno_to_be_err(err);
1002 1034 free(tmp_menu);
1003 1035 tmp_menu = NULL;
1004 1036 goto cleanup;
1005 1037 }
1006 1038 if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
1007 1039 err = errno;
1008 1040 be_print_err(gettext("be_remove_menu: "
1009 1041 "could not open tmp file for write: %s\n"),
1010 1042 strerror(err));
1011 1043 (void) close(fd);
1012 1044 ret = errno_to_be_err(err);
1013 1045 goto cleanup;
1014 1046 }
1015 1047
1016 1048 while (fgets(menu_buf, BUFSIZ, menu_fp)) {
1017 1049 char tline [BUFSIZ];
1018 1050 char *tok = NULL;
1019 1051
1020 1052 (void) strlcpy(tline, menu_buf, sizeof (tline));
1021 1053
1022 1054 /* Tokenize line */
1023 1055 tok = strtok(tline, BE_WHITE_SPACE);
1024 1056
1025 1057 if (tok == NULL) {
1026 1058 /* Found empty line, write it out */
1027 1059 (void) fputs(menu_buf, tmp_menu_fp);
1028 1060 } else if (strcmp(tok, "default") == 0) {
1029 1061 /* Found the default line, adjust it */
1030 1062 (void) snprintf(tline, sizeof (tline),
1031 1063 "default %d\n", default_entry);
1032 1064
1033 1065 (void) fputs(tline, tmp_menu_fp);
1034 1066 } else {
1035 1067 /* Pass through all other lines */
1036 1068 (void) fputs(menu_buf, tmp_menu_fp);
1037 1069 }
1038 1070 }
1039 1071
1040 1072 (void) fclose(menu_fp);
1041 1073 menu_fp = NULL;
1042 1074 (void) fclose(tmp_menu_fp);
1043 1075 tmp_menu_fp = NULL;
1044 1076
1045 1077 /* Copy the modified menu.lst into place */
1046 1078 if (rename(tmp_menu, menu) != 0) {
1047 1079 err = errno;
1048 1080 be_print_err(gettext("be_remove_menu: "
1049 1081 "failed to rename file %s to %s: %s\n"),
1050 1082 tmp_menu, menu, strerror(err));
1051 1083 ret = errno_to_be_err(err);
1052 1084 goto cleanup;
1053 1085 }
1054 1086
1055 1087 free(tmp_menu);
1056 1088 tmp_menu = NULL;
1057 1089 }
1058 1090 }
1059 1091
1060 1092 /* Set the perms and ownership of the updated file */
1061 1093 if (chmod(menu, sb.st_mode) != 0) {
1062 1094 err = errno;
1063 1095 be_print_err(gettext("be_remove_menu: "
1064 1096 "failed to chmod %s: %s\n"), menu, strerror(err));
1065 1097 ret = errno_to_be_err(err);
1066 1098 goto cleanup;
1067 1099 }
1068 1100 if (chown(menu, sb.st_uid, sb.st_gid) != 0) {
1069 1101 err = errno;
1070 1102 be_print_err(gettext("be_remove_menu: "
1071 1103 "failed to chown %s: %s\n"), menu, strerror(err));
1072 1104 ret = errno_to_be_err(err);
1073 1105 goto cleanup;
1074 1106 }
1075 1107
1076 1108 cleanup:
1077 1109 if (pool_mounted) {
1078 1110 int err = BE_SUCCESS;
1079 1111 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1080 1112 if (ret == BE_SUCCESS)
1081 1113 ret = err;
1082 1114 free(orig_mntpnt);
1083 1115 free(ptmp_mntpnt);
1084 1116 }
1085 1117 ZFS_CLOSE(zhp);
1086 1118
1087 1119 free(buffer);
1088 1120 if (menu_fp != NULL)
1089 1121 (void) fclose(menu_fp);
1090 1122 if (tmp_menu_fp != NULL)
1091 1123 (void) fclose(tmp_menu_fp);
1092 1124 if (tmp_menu != NULL) {
1093 1125 (void) unlink(tmp_menu);
1094 1126 free(tmp_menu);
1095 1127 }
1096 1128
1097 1129 return (ret);
1098 1130 }
1099 1131
1100 1132 /*
1101 1133 * Function: be_default_grub_bootfs
1102 1134 * Description: This function returns the dataset in the default entry of
1103 1135 * the grub menu. If no default entry is found with a valid bootfs
1104 1136 * entry NULL is returned.
1105 1137 * Parameters:
1106 1138 * be_root_pool - This is the name of the root pool where the
1107 1139 * grub menu can be found.
1108 1140 * def_bootfs - This is used to pass back the bootfs string. On
1109 1141 * error NULL is returned here.
1110 1142 * Returns:
1111 1143 * Success - BE_SUCCESS is returned.
1112 1144 * Failure - a be_errno_t is returned.
1113 1145 * Scope:
1114 1146 * Semi-private (library wide use only)
1115 1147 */
1116 1148 int
1117 1149 be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs)
1118 1150 {
1119 1151 zfs_handle_t *zhp = NULL;
1120 1152 char grub_file[MAXPATHLEN];
1121 1153 FILE *menu_fp;
1122 1154 char line[BUFSIZ];
1123 1155 char *pool_mntpnt = NULL;
1124 1156 char *ptmp_mntpnt = NULL;
1125 1157 char *orig_mntpnt = NULL;
1126 1158 int default_entry = 0, entries = 0;
1127 1159 int found_default = 0;
1128 1160 int ret = BE_SUCCESS;
1129 1161 boolean_t pool_mounted = B_FALSE;
1130 1162
1131 1163 errno = 0;
1132 1164
1133 1165 /*
1134 1166 * Check to see if this system supports grub
1135 1167 */
1136 1168 if (!be_has_grub()) {
1137 1169 be_print_err(gettext("be_default_grub_bootfs: operation "
1138 1170 "not supported on this architecture\n"));
1139 1171 return (BE_ERR_NOTSUP);
1140 1172 }
1141 1173
1142 1174 *def_bootfs = NULL;
1143 1175
1144 1176 /* Get handle to pool dataset */
1145 1177 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1146 1178 be_print_err(gettext("be_default_grub_bootfs: "
1147 1179 "failed to open pool dataset for %s: %s"),
1148 1180 be_root_pool, libzfs_error_description(g_zfs));
1149 1181 return (zfs_err_to_be_err(g_zfs));
1150 1182 }
1151 1183
1152 1184 /*
1153 1185 * Check to see if the pool's dataset is mounted. If it isn't we'll
1154 1186 * attempt to mount it.
1155 1187 */
1156 1188 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1157 1189 &pool_mounted)) != BE_SUCCESS) {
1158 1190 be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1159 1191 "(%s) could not be mounted\n"), be_root_pool);
1160 1192 ZFS_CLOSE(zhp);
1161 1193 return (ret);
1162 1194 }
1163 1195
1164 1196 /*
1165 1197 * Get the mountpoint for the root pool dataset.
1166 1198 */
1167 1199 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1168 1200 be_print_err(gettext("be_default_grub_bootfs: failed "
1169 1201 "to get mount point for the root pool. Can't set "
1170 1202 "the default BE in the grub menu.\n"));
1171 1203 ret = BE_ERR_NO_MENU;
1172 1204 goto cleanup;
1173 1205 }
1174 1206
1175 1207 (void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1176 1208 pool_mntpnt, BE_GRUB_MENU);
1177 1209
1178 1210 if ((ret = be_open_menu((char *)be_root_pool, grub_file,
1179 1211 &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
1180 1212 goto cleanup;
1181 1213 } else if (menu_fp == NULL) {
1182 1214 ret = BE_ERR_NO_MENU;
1183 1215 goto cleanup;
1184 1216 }
1185 1217
1186 1218 free(pool_mntpnt);
1187 1219 pool_mntpnt = NULL;
1188 1220
1189 1221 while (fgets(line, BUFSIZ, menu_fp)) {
1190 1222 char *tok = strtok(line, BE_WHITE_SPACE);
1191 1223
1192 1224 if (tok != NULL && tok[0] != '#') {
1193 1225 if (!found_default) {
1194 1226 if (strcmp(tok, "default") == 0) {
1195 1227 tok = strtok(NULL, BE_WHITE_SPACE);
1196 1228 if (tok != NULL) {
1197 1229 default_entry = atoi(tok);
1198 1230 rewind(menu_fp);
1199 1231 found_default = 1;
1200 1232 }
1201 1233 }
1202 1234 continue;
1203 1235 }
1204 1236 if (strcmp(tok, "title") == 0) {
1205 1237 entries++;
1206 1238 } else if (default_entry == entries - 1) {
1207 1239 if (strcmp(tok, "bootfs") == 0) {
1208 1240 tok = strtok(NULL, BE_WHITE_SPACE);
1209 1241 (void) fclose(menu_fp);
1210 1242
1211 1243 if (tok == NULL) {
1212 1244 ret = BE_SUCCESS;
1213 1245 goto cleanup;
1214 1246 }
1215 1247
1216 1248 if ((*def_bootfs = strdup(tok)) !=
1217 1249 NULL) {
1218 1250 ret = BE_SUCCESS;
1219 1251 goto cleanup;
1220 1252 }
1221 1253 be_print_err(gettext(
1222 1254 "be_default_grub_bootfs: "
1223 1255 "memory allocation failed\n"));
1224 1256 ret = BE_ERR_NOMEM;
1225 1257 goto cleanup;
1226 1258 }
1227 1259 } else if (default_entry < entries - 1) {
1228 1260 /*
1229 1261 * no bootfs entry for the default entry.
1230 1262 */
1231 1263 break;
1232 1264 }
1233 1265 }
1234 1266 }
1235 1267 (void) fclose(menu_fp);
1236 1268
1237 1269 cleanup:
1238 1270 if (pool_mounted) {
1239 1271 int err = BE_SUCCESS;
1240 1272 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1241 1273 if (ret == BE_SUCCESS)
1242 1274 ret = err;
1243 1275 free(orig_mntpnt);
1244 1276 free(ptmp_mntpnt);
1245 1277 }
1246 1278 ZFS_CLOSE(zhp);
1247 1279 return (ret);
1248 1280 }
1249 1281
1250 1282 /*
1251 1283 * Function: be_change_grub_default
1252 1284 * Description: This function takes two parameters. These are the name of
1253 1285 * the BE we want to have as the default booted in the grub
1254 1286 * menu and the root pool where the path to the grub menu exists.
1255 1287 * The code takes this and finds the BE's entry in the grub menu
1256 1288 * and changes the default entry to point to that entry in the
1257 1289 * list.
1258 1290 * Parameters:
1259 1291 * be_name - This is the name of the BE wanted as the default
1260 1292 * for the next boot.
1261 1293 * be_root_pool - This is the name of the root pool where the
1262 1294 * grub menu can be found.
1263 1295 * Returns:
1264 1296 * BE_SUCCESS - Success
1265 1297 * be_errno_t - Failure
1266 1298 * Scope:
1267 1299 * Semi-private (library wide use only)
1268 1300 */
1269 1301 int
1270 1302 be_change_grub_default(char *be_name, char *be_root_pool)
1271 1303 {
1272 1304 zfs_handle_t *zhp = NULL;
1273 1305 char grub_file[MAXPATHLEN];
1274 1306 char *temp_grub;
1275 1307 char *pool_mntpnt = NULL;
1276 1308 char *ptmp_mntpnt = NULL;
1277 1309 char *orig_mntpnt = NULL;
1278 1310 char line[BUFSIZ];
1279 1311 char temp_line[BUFSIZ];
1280 1312 char be_root_ds[MAXPATHLEN];
1281 1313 FILE *grub_fp = NULL;
1282 1314 FILE *temp_fp = NULL;
1283 1315 struct stat sb;
1284 1316 int temp_grub_len = 0;
1285 1317 int fd, entries = 0;
1286 1318 int err = 0;
1287 1319 int ret = BE_SUCCESS;
1288 1320 boolean_t found_default = B_FALSE;
1289 1321 boolean_t pool_mounted = B_FALSE;
1290 1322
1291 1323 errno = 0;
1292 1324
1293 1325 /*
1294 1326 * Check to see if this system supports grub
1295 1327 */
1296 1328 if (!be_has_grub()) {
1297 1329 be_print_err(gettext("be_change_grub_default: operation "
1298 1330 "not supported on this architecture\n"));
1299 1331 return (BE_ERR_NOTSUP);
1300 1332 }
1301 1333
1302 1334 /* Generate string for BE's root dataset */
1303 1335 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
1304 1336
1305 1337 /* Get handle to pool dataset */
1306 1338 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1307 1339 be_print_err(gettext("be_change_grub_default: "
1308 1340 "failed to open pool dataset for %s: %s"),
1309 1341 be_root_pool, libzfs_error_description(g_zfs));
1310 1342 return (zfs_err_to_be_err(g_zfs));
1311 1343 }
1312 1344
1313 1345 /*
1314 1346 * Check to see if the pool's dataset is mounted. If it isn't we'll
1315 1347 * attempt to mount it.
1316 1348 */
1317 1349 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1318 1350 &pool_mounted)) != BE_SUCCESS) {
1319 1351 be_print_err(gettext("be_change_grub_default: pool dataset "
1320 1352 "(%s) could not be mounted\n"), be_root_pool);
1321 1353 ZFS_CLOSE(zhp);
1322 1354 return (ret);
1323 1355 }
1324 1356
1325 1357 /*
1326 1358 * Get the mountpoint for the root pool dataset.
1327 1359 */
1328 1360 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1329 1361 be_print_err(gettext("be_change_grub_default: pool "
1330 1362 "dataset (%s) is not mounted. Can't set "
1331 1363 "the default BE in the grub menu.\n"), be_root_pool);
1332 1364 ret = BE_ERR_NO_MENU;
1333 1365 goto cleanup;
1334 1366 }
1335 1367
1336 1368 (void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1337 1369 pool_mntpnt, BE_GRUB_MENU);
1338 1370
1339 1371 if ((ret = be_open_menu(be_root_pool, grub_file,
1340 1372 &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
1341 1373 goto cleanup;
1342 1374 } else if (grub_fp == NULL) {
1343 1375 ret = BE_ERR_NO_MENU;
1344 1376 goto cleanup;
1345 1377 }
1346 1378
1347 1379 free(pool_mntpnt);
1348 1380 pool_mntpnt = NULL;
1349 1381
1350 1382 /* Grab the stats of the original menu file */
1351 1383 if (stat(grub_file, &sb) != 0) {
1352 1384 err = errno;
1353 1385 be_print_err(gettext("be_change_grub_default: "
1354 1386 "failed to stat file %s: %s\n"), grub_file, strerror(err));
1355 1387 ret = errno_to_be_err(err);
1356 1388 goto cleanup;
1357 1389 }
1358 1390
1359 1391 /* Create a tmp file for the modified menu.lst */
1360 1392 temp_grub_len = strlen(grub_file) + 7;
1361 1393 if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) {
1362 1394 be_print_err(gettext("be_change_grub_default: "
1363 1395 "malloc failed\n"));
1364 1396 ret = BE_ERR_NOMEM;
1365 1397 goto cleanup;
1366 1398 }
1367 1399 (void) memset(temp_grub, 0, temp_grub_len);
1368 1400 (void) strlcpy(temp_grub, grub_file, temp_grub_len);
1369 1401 (void) strlcat(temp_grub, "XXXXXX", temp_grub_len);
1370 1402 if ((fd = mkstemp(temp_grub)) == -1) {
1371 1403 err = errno;
1372 1404 be_print_err(gettext("be_change_grub_default: "
1373 1405 "mkstemp failed: %s\n"), strerror(err));
1374 1406 ret = errno_to_be_err(err);
1375 1407 free(temp_grub);
1376 1408 temp_grub = NULL;
1377 1409 goto cleanup;
1378 1410 }
1379 1411 if ((temp_fp = fdopen(fd, "w")) == NULL) {
1380 1412 err = errno;
1381 1413 be_print_err(gettext("be_change_grub_default: "
1382 1414 "failed to open %s file: %s\n"),
1383 1415 temp_grub, strerror(err));
1384 1416 (void) close(fd);
1385 1417 ret = errno_to_be_err(err);
1386 1418 goto cleanup;
1387 1419 }
1388 1420
1389 1421 while (fgets(line, BUFSIZ, grub_fp)) {
1390 1422 char *tok = strtok(line, BE_WHITE_SPACE);
1391 1423
1392 1424 if (tok == NULL || tok[0] == '#') {
1393 1425 continue;
1394 1426 } else if (strcmp(tok, "title") == 0) {
1395 1427 entries++;
1396 1428 continue;
1397 1429 } else if (strcmp(tok, "bootfs") == 0) {
1398 1430 char *bootfs = strtok(NULL, BE_WHITE_SPACE);
1399 1431 if (bootfs == NULL)
1400 1432 continue;
1401 1433
1402 1434 if (strcmp(bootfs, be_root_ds) == 0) {
1403 1435 found_default = B_TRUE;
1404 1436 break;
1405 1437 }
1406 1438 }
1407 1439 }
1408 1440
1409 1441 if (!found_default) {
1410 1442 be_print_err(gettext("be_change_grub_default: failed "
1411 1443 "to find entry for %s in the grub menu\n"),
1412 1444 be_name);
1413 1445 ret = BE_ERR_BE_NOENT;
1414 1446 goto cleanup;
1415 1447 }
1416 1448
1417 1449 rewind(grub_fp);
1418 1450
1419 1451 while (fgets(line, BUFSIZ, grub_fp)) {
1420 1452 char *tok = NULL;
1421 1453
1422 1454 (void) strncpy(temp_line, line, BUFSIZ);
1423 1455
1424 1456 if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
1425 1457 strcmp(tok, "default") == 0) {
1426 1458 (void) snprintf(temp_line, BUFSIZ, "default %d\n",
1427 1459 entries - 1 >= 0 ? entries - 1 : 0);
1428 1460 (void) fputs(temp_line, temp_fp);
1429 1461 } else {
1430 1462 (void) fputs(line, temp_fp);
1431 1463 }
1432 1464 }
1433 1465
1434 1466 (void) fclose(grub_fp);
1435 1467 grub_fp = NULL;
1436 1468 (void) fclose(temp_fp);
1437 1469 temp_fp = NULL;
1438 1470
1439 1471 if (rename(temp_grub, grub_file) != 0) {
1440 1472 err = errno;
1441 1473 be_print_err(gettext("be_change_grub_default: "
1442 1474 "failed to rename file %s to %s: %s\n"),
1443 1475 temp_grub, grub_file, strerror(err));
1444 1476 ret = errno_to_be_err(err);
1445 1477 goto cleanup;
1446 1478 }
1447 1479 free(temp_grub);
1448 1480 temp_grub = NULL;
1449 1481
1450 1482 /* Set the perms and ownership of the updated file */
1451 1483 if (chmod(grub_file, sb.st_mode) != 0) {
1452 1484 err = errno;
1453 1485 be_print_err(gettext("be_change_grub_default: "
1454 1486 "failed to chmod %s: %s\n"), grub_file, strerror(err));
1455 1487 ret = errno_to_be_err(err);
1456 1488 goto cleanup;
1457 1489 }
1458 1490 if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) {
1459 1491 err = errno;
1460 1492 be_print_err(gettext("be_change_grub_default: "
1461 1493 "failed to chown %s: %s\n"), grub_file, strerror(err));
1462 1494 ret = errno_to_be_err(err);
1463 1495 }
1464 1496
1465 1497 cleanup:
1466 1498 if (pool_mounted) {
1467 1499 int err = BE_SUCCESS;
1468 1500 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1469 1501 if (ret == BE_SUCCESS)
1470 1502 ret = err;
1471 1503 free(orig_mntpnt);
1472 1504 free(ptmp_mntpnt);
1473 1505 }
1474 1506 ZFS_CLOSE(zhp);
1475 1507 if (grub_fp != NULL)
1476 1508 (void) fclose(grub_fp);
1477 1509 if (temp_fp != NULL)
1478 1510 (void) fclose(temp_fp);
1479 1511 if (temp_grub != NULL) {
1480 1512 (void) unlink(temp_grub);
1481 1513 free(temp_grub);
1482 1514 }
1483 1515
1484 1516 return (ret);
1485 1517 }
1486 1518
1487 1519 /*
1488 1520 * Function: be_update_menu
1489 1521 * Description: This function is used by be_rename to change the BE name in
1490 1522 * an existing entry in the grub menu to the new name of the BE.
1491 1523 * Parameters:
1492 1524 * be_orig_name - the original name of the BE
1493 1525 * be_new_name - the new name the BE is being renameed to.
1494 1526 * be_root_pool - The pool which contains the grub menu
1495 1527 * boot_pool - the pool where the BE is, if different than
1496 1528 * the pool containing the boot menu. If this is
1497 1529 * NULL it will be set to be_root_pool.
1498 1530 * Returns:
1499 1531 * BE_SUCCESS - Success
1500 1532 * be_errno_t - Failure
1501 1533 * Scope:
1502 1534 * Semi-private (library wide use only)
1503 1535 */
1504 1536 int
1505 1537 be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool,
1506 1538 char *boot_pool)
1507 1539 {
1508 1540 zfs_handle_t *zhp = NULL;
1509 1541 char menu_file[MAXPATHLEN];
1510 1542 char be_root_ds[MAXPATHLEN];
1511 1543 char be_new_root_ds[MAXPATHLEN];
1512 1544 char line[BUFSIZ];
1513 1545 char *pool_mntpnt = NULL;
1514 1546 char *ptmp_mntpnt = NULL;
1515 1547 char *orig_mntpnt = NULL;
1516 1548 char *temp_menu = NULL;
1517 1549 FILE *menu_fp = NULL;
1518 1550 FILE *new_fp = NULL;
1519 1551 struct stat sb;
1520 1552 int temp_menu_len = 0;
1521 1553 int tmp_fd;
1522 1554 int ret = BE_SUCCESS;
1523 1555 int err = 0;
1524 1556 boolean_t pool_mounted = B_FALSE;
1525 1557
1526 1558 errno = 0;
1527 1559
1528 1560 if (boot_pool == NULL)
1529 1561 boot_pool = be_root_pool;
1530 1562
1531 1563 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1532 1564 be_print_err(gettext("be_update_menu: failed to open "
1533 1565 "pool dataset for %s: %s\n"), be_root_pool,
1534 1566 libzfs_error_description(g_zfs));
1535 1567 return (zfs_err_to_be_err(g_zfs));
1536 1568 }
1537 1569
1538 1570 /*
1539 1571 * Check to see if the pool's dataset is mounted. If it isn't we'll
1540 1572 * attempt to mount it.
1541 1573 */
1542 1574 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1543 1575 &pool_mounted)) != BE_SUCCESS) {
1544 1576 be_print_err(gettext("be_update_menu: pool dataset "
1545 1577 "(%s) could not be mounted\n"), be_root_pool);
1546 1578 ZFS_CLOSE(zhp);
1547 1579 return (ret);
1548 1580 }
1549 1581
1550 1582 /*
1551 1583 * Get the mountpoint for the root pool dataset.
1552 1584 */
1553 1585 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1554 1586 be_print_err(gettext("be_update_menu: failed "
1555 1587 "to get mount point for the root pool. Can't set "
1556 1588 "the default BE in the grub menu.\n"));
1557 1589 ret = BE_ERR_NO_MENU;
1558 1590 goto cleanup;
1559 1591 }
1560 1592
1561 1593 /*
1562 1594 * Check to see if this system supports grub
1563 1595 */
1564 1596 if (be_has_grub()) {
1565 1597 (void) snprintf(menu_file, sizeof (menu_file),
1566 1598 "%s%s", pool_mntpnt, BE_GRUB_MENU);
1567 1599 } else {
1568 1600 (void) snprintf(menu_file, sizeof (menu_file),
1569 1601 "%s%s", pool_mntpnt, BE_SPARC_MENU);
1570 1602 }
1571 1603
1572 1604 be_make_root_ds(be_root_pool, be_orig_name, be_root_ds,
1573 1605 sizeof (be_root_ds));
1574 1606 be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
1575 1607 sizeof (be_new_root_ds));
1576 1608
1577 1609 if ((ret = be_open_menu(be_root_pool, menu_file,
1578 1610 &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
1579 1611 goto cleanup;
1580 1612 } else if (menu_fp == NULL) {
1581 1613 ret = BE_ERR_NO_MENU;
1582 1614 goto cleanup;
1583 1615 }
1584 1616
1585 1617 free(pool_mntpnt);
1586 1618 pool_mntpnt = NULL;
1587 1619
1588 1620 /* Grab the stat of the original menu file */
1589 1621 if (stat(menu_file, &sb) != 0) {
1590 1622 err = errno;
1591 1623 be_print_err(gettext("be_update_menu: "
1592 1624 "failed to stat file %s: %s\n"), menu_file, strerror(err));
1593 1625 (void) fclose(menu_fp);
1594 1626 ret = errno_to_be_err(err);
1595 1627 goto cleanup;
1596 1628 }
1597 1629
1598 1630 /* Create tmp file for modified menu.lst */
1599 1631 temp_menu_len = strlen(menu_file) + 7;
1600 1632 if ((temp_menu = (char *)malloc(temp_menu_len))
1601 1633 == NULL) {
1602 1634 be_print_err(gettext("be_update_menu: "
1603 1635 "malloc failed\n"));
1604 1636 (void) fclose(menu_fp);
1605 1637 ret = BE_ERR_NOMEM;
1606 1638 goto cleanup;
1607 1639 }
1608 1640 (void) memset(temp_menu, 0, temp_menu_len);
1609 1641 (void) strlcpy(temp_menu, menu_file, temp_menu_len);
1610 1642 (void) strlcat(temp_menu, "XXXXXX", temp_menu_len);
1611 1643 if ((tmp_fd = mkstemp(temp_menu)) == -1) {
1612 1644 err = errno;
1613 1645 be_print_err(gettext("be_update_menu: "
1614 1646 "mkstemp failed: %s\n"), strerror(err));
1615 1647 (void) fclose(menu_fp);
1616 1648 free(temp_menu);
1617 1649 ret = errno_to_be_err(err);
1618 1650 goto cleanup;
1619 1651 }
1620 1652 if ((new_fp = fdopen(tmp_fd, "w")) == NULL) {
1621 1653 err = errno;
1622 1654 be_print_err(gettext("be_update_menu: "
1623 1655 "fdopen failed: %s\n"), strerror(err));
1624 1656 (void) close(tmp_fd);
1625 1657 (void) fclose(menu_fp);
1626 1658 free(temp_menu);
1627 1659 ret = errno_to_be_err(err);
1628 1660 goto cleanup;
1629 1661 }
1630 1662
1631 1663 while (fgets(line, BUFSIZ, menu_fp)) {
1632 1664 char tline[BUFSIZ];
1633 1665 char new_line[BUFSIZ];
1634 1666 char *c = NULL;
1635 1667
1636 1668 (void) strlcpy(tline, line, sizeof (tline));
1637 1669
1638 1670 /* Tokenize line */
1639 1671 c = strtok(tline, BE_WHITE_SPACE);
1640 1672
1641 1673 if (c == NULL) {
1642 1674 /* Found empty line, write it out. */
1643 1675 (void) fputs(line, new_fp);
1644 1676 } else if (c[0] == '#') {
1645 1677 /* Found a comment line, write it out. */
1646 1678 (void) fputs(line, new_fp);
1647 1679 } else if (strcmp(c, "title") == 0) {
1648 1680 char *name = NULL;
1649 1681 char *desc = NULL;
1650 1682
1651 1683 /*
1652 1684 * Found a 'title' line, parse out BE name or
1653 1685 * the description.
1654 1686 */
1655 1687 name = strtok(NULL, BE_WHITE_SPACE);
1656 1688
1657 1689 if (name == NULL) {
1658 1690 /*
1659 1691 * Nothing after 'title', just push
1660 1692 * this line through
1661 1693 */
1662 1694 (void) fputs(line, new_fp);
1663 1695 } else {
1664 1696 /*
1665 1697 * Grab the remainder of the title which
1666 1698 * could be a multi worded description
1667 1699 */
1668 1700 desc = strtok(NULL, "\n");
1669 1701
1670 1702 if (strcmp(name, be_orig_name) == 0) {
1671 1703 /*
1672 1704 * The first token of the title is
1673 1705 * the old BE name, replace it with
1674 1706 * the new one, and write it out
1675 1707 * along with the remainder of
1676 1708 * description if there is one.
1677 1709 */
1678 1710 if (desc) {
1679 1711 (void) snprintf(new_line,
1680 1712 sizeof (new_line),
1681 1713 "title %s %s\n",
1682 1714 be_new_name, desc);
1683 1715 } else {
1684 1716 (void) snprintf(new_line,
1685 1717 sizeof (new_line),
1686 1718 "title %s\n", be_new_name);
1687 1719 }
1688 1720
1689 1721 (void) fputs(new_line, new_fp);
1690 1722 } else {
1691 1723 (void) fputs(line, new_fp);
1692 1724 }
1693 1725 }
1694 1726 } else if (strcmp(c, "bootfs") == 0) {
1695 1727 /*
1696 1728 * Found a 'bootfs' line, parse out the BE root
1697 1729 * dataset value.
1698 1730 */
1699 1731 char *root_ds = strtok(NULL, BE_WHITE_SPACE);
1700 1732
1701 1733 if (root_ds == NULL) {
1702 1734 /*
1703 1735 * Nothing after 'bootfs', just push
1704 1736 * this line through
1705 1737 */
1706 1738 (void) fputs(line, new_fp);
1707 1739 } else {
1708 1740 /*
1709 1741 * If this bootfs is the one we're renaming,
1710 1742 * write out the new root dataset value
1711 1743 */
1712 1744 if (strcmp(root_ds, be_root_ds) == 0) {
1713 1745 (void) snprintf(new_line,
1714 1746 sizeof (new_line), "bootfs %s\n",
1715 1747 be_new_root_ds);
1716 1748
1717 1749 (void) fputs(new_line, new_fp);
1718 1750 } else {
1719 1751 (void) fputs(line, new_fp);
1720 1752 }
1721 1753 }
1722 1754 } else {
1723 1755 /*
1724 1756 * Found some other line we don't care
1725 1757 * about, write it out.
1726 1758 */
1727 1759 (void) fputs(line, new_fp);
1728 1760 }
1729 1761 }
1730 1762
1731 1763 (void) fclose(menu_fp);
1732 1764 (void) fclose(new_fp);
1733 1765 (void) close(tmp_fd);
1734 1766
1735 1767 if (rename(temp_menu, menu_file) != 0) {
1736 1768 err = errno;
1737 1769 be_print_err(gettext("be_update_menu: "
1738 1770 "failed to rename file %s to %s: %s\n"),
1739 1771 temp_menu, menu_file, strerror(err));
1740 1772 ret = errno_to_be_err(err);
1741 1773 }
1742 1774 free(temp_menu);
1743 1775
1744 1776 /* Set the perms and ownership of the updated file */
1745 1777 if (chmod(menu_file, sb.st_mode) != 0) {
1746 1778 err = errno;
1747 1779 be_print_err(gettext("be_update_menu: "
1748 1780 "failed to chmod %s: %s\n"), menu_file, strerror(err));
1749 1781 ret = errno_to_be_err(err);
1750 1782 goto cleanup;
1751 1783 }
1752 1784 if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) {
1753 1785 err = errno;
1754 1786 be_print_err(gettext("be_update_menu: "
1755 1787 "failed to chown %s: %s\n"), menu_file, strerror(err));
1756 1788 ret = errno_to_be_err(err);
1757 1789 }
1758 1790
1759 1791 cleanup:
1760 1792 if (pool_mounted) {
1761 1793 int err = BE_SUCCESS;
1762 1794 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1763 1795 if (ret == BE_SUCCESS)
1764 1796 ret = err;
1765 1797 free(orig_mntpnt);
1766 1798 free(ptmp_mntpnt);
1767 1799 }
1768 1800 ZFS_CLOSE(zhp);
1769 1801 return (ret);
1770 1802 }
1771 1803
1772 1804 /*
1773 1805 * Function: be_has_menu_entry
1774 1806 * Description: Checks to see if the BEs root dataset has an entry in the grub
1775 1807 * menu.
1776 1808 * Parameters:
1777 1809 * be_dataset - The root dataset of the BE
1778 1810 * be_root_pool - The pool which contains the boot menu
1779 1811 * entry - A pointer the the entry number of the BE if found.
1780 1812 * Returns:
1781 1813 * B_TRUE - Success
1782 1814 * B_FALSE - Failure
1783 1815 * Scope:
1784 1816 * Semi-private (library wide use only)
1785 1817 */
1786 1818 boolean_t
1787 1819 be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry)
1788 1820 {
1789 1821 zfs_handle_t *zhp = NULL;
1790 1822 char menu_file[MAXPATHLEN];
1791 1823 FILE *menu_fp;
1792 1824 char line[BUFSIZ];
1793 1825 char *last;
1794 1826 char *rpool_mntpnt = NULL;
1795 1827 char *ptmp_mntpnt = NULL;
1796 1828 char *orig_mntpnt = NULL;
1797 1829 int ent_num = 0;
1798 1830 boolean_t ret = 0;
1799 1831 boolean_t pool_mounted = B_FALSE;
1800 1832
1801 1833
1802 1834 /*
1803 1835 * Check to see if this system supports grub
1804 1836 */
1805 1837 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1806 1838 be_print_err(gettext("be_has_menu_entry: failed to open "
1807 1839 "pool dataset for %s: %s\n"), be_root_pool,
1808 1840 libzfs_error_description(g_zfs));
1809 1841 return (B_FALSE);
1810 1842 }
1811 1843
1812 1844 /*
1813 1845 * Check to see if the pool's dataset is mounted. If it isn't we'll
1814 1846 * attempt to mount it.
1815 1847 */
1816 1848 if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1817 1849 &pool_mounted) != 0) {
1818 1850 be_print_err(gettext("be_has_menu_entry: pool dataset "
1819 1851 "(%s) could not be mounted\n"), be_root_pool);
1820 1852 ZFS_CLOSE(zhp);
1821 1853 return (B_FALSE);
1822 1854 }
1823 1855
1824 1856 /*
1825 1857 * Get the mountpoint for the root pool dataset.
1826 1858 */
1827 1859 if (!zfs_is_mounted(zhp, &rpool_mntpnt)) {
1828 1860 be_print_err(gettext("be_has_menu_entry: pool "
1829 1861 "dataset (%s) is not mounted. Can't set "
1830 1862 "the default BE in the grub menu.\n"), be_root_pool);
1831 1863 ret = B_FALSE;
1832 1864 goto cleanup;
1833 1865 }
1834 1866
1835 1867 if (be_has_grub()) {
1836 1868 (void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1837 1869 rpool_mntpnt, BE_GRUB_MENU);
1838 1870 } else {
1839 1871 (void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1840 1872 rpool_mntpnt, BE_SPARC_MENU);
1841 1873 }
1842 1874
1843 1875 if (be_open_menu(be_root_pool, menu_file, &menu_fp, "r",
1844 1876 B_FALSE) != 0) {
1845 1877 ret = B_FALSE;
1846 1878 goto cleanup;
1847 1879 } else if (menu_fp == NULL) {
1848 1880 ret = B_FALSE;
1849 1881 goto cleanup;
1850 1882 }
1851 1883
1852 1884 free(rpool_mntpnt);
1853 1885 rpool_mntpnt = NULL;
1854 1886
1855 1887 while (fgets(line, BUFSIZ, menu_fp)) {
1856 1888 char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
1857 1889
1858 1890 if (tok != NULL && tok[0] != '#') {
1859 1891 if (strcmp(tok, "bootfs") == 0) {
1860 1892 tok = strtok_r(last, BE_WHITE_SPACE, &last);
1861 1893 if (tok != NULL && strcmp(tok,
1862 1894 be_dataset) == 0) {
1863 1895 (void) fclose(menu_fp);
1864 1896 /*
1865 1897 * The entry number needs to be
1866 1898 * decremented here because the title
1867 1899 * will always be the first line for
1868 1900 * an entry. Because of this we'll
1869 1901 * always be off by one entry when we
1870 1902 * check for bootfs.
1871 1903 */
1872 1904 *entry = ent_num - 1;
1873 1905 ret = B_TRUE;
1874 1906 goto cleanup;
1875 1907 }
1876 1908 } else if (strcmp(tok, "title") == 0)
1877 1909 ent_num++;
1878 1910 }
1879 1911 }
1880 1912
1881 1913 cleanup:
1882 1914 if (pool_mounted) {
1883 1915 (void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1884 1916 free(orig_mntpnt);
1885 1917 free(ptmp_mntpnt);
1886 1918 }
1887 1919 ZFS_CLOSE(zhp);
1888 1920 (void) fclose(menu_fp);
1889 1921 return (ret);
1890 1922 }
1891 1923
1892 1924 /*
1893 1925 * Function: be_update_vfstab
1894 1926 * Description: This function digs into a BE's vfstab and updates all
1895 1927 * entries with file systems listed in be_fs_list_data_t.
1896 1928 * The entry's root container dataset and be_name will be
1897 1929 * updated with the parameters passed in.
1898 1930 * Parameters:
1899 1931 * be_name - name of BE to update
1900 1932 * old_rc_loc - dataset under which the root container dataset
1901 1933 * of the old BE resides in.
1902 1934 * new_rc_loc - dataset under which the root container dataset
1903 1935 * of the new BE resides in.
1904 1936 * fld - be_fs_list_data_t pointer providing the list of
1905 1937 * file systems to look for in vfstab.
1906 1938 * mountpoint - directory of where BE is currently mounted.
1907 1939 * If NULL, then BE is not currently mounted.
1908 1940 * Returns:
1909 1941 * BE_SUCCESS - Success
1910 1942 * be_errno_t - Failure
1911 1943 * Scope:
1912 1944 * Semi-private (library wide use only)
1913 1945 */
1914 1946 int
1915 1947 be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc,
1916 1948 be_fs_list_data_t *fld, char *mountpoint)
1917 1949 {
1918 1950 char *tmp_mountpoint = NULL;
1919 1951 char alt_vfstab[MAXPATHLEN];
1920 1952 int ret = BE_SUCCESS, err = BE_SUCCESS;
1921 1953
1922 1954 if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0)
1923 1955 return (BE_SUCCESS);
1924 1956
1925 1957 /* If BE not already mounted, mount the BE */
1926 1958 if (mountpoint == NULL) {
1927 1959 if ((ret = _be_mount(be_name, &tmp_mountpoint,
1928 1960 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1929 1961 be_print_err(gettext("be_update_vfstab: "
1930 1962 "failed to mount BE (%s)\n"), be_name);
1931 1963 return (ret);
1932 1964 }
1933 1965 } else {
1934 1966 tmp_mountpoint = mountpoint;
1935 1967 }
1936 1968
1937 1969 /* Get string for vfstab in the mounted BE. */
1938 1970 (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1939 1971 tmp_mountpoint);
1940 1972
1941 1973 /* Update the vfstab */
1942 1974 ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
1943 1975 fld);
1944 1976
1945 1977 /* Unmount BE if we mounted it */
1946 1978 if (mountpoint == NULL) {
1947 1979 if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) {
1948 1980 /* Remove temporary mountpoint */
1949 1981 (void) rmdir(tmp_mountpoint);
1950 1982 } else {
1951 1983 be_print_err(gettext("be_update_vfstab: "
1952 1984 "failed to unmount BE %s mounted at %s\n"),
1953 1985 be_name, tmp_mountpoint);
1954 1986 if (ret == BE_SUCCESS)
1955 1987 ret = err;
1956 1988 }
1957 1989
1958 1990 free(tmp_mountpoint);
1959 1991 }
1960 1992
1961 1993 return (ret);
1962 1994 }
1963 1995
1964 1996 /*
1965 1997 * Function: be_update_zone_vfstab
1966 1998 * Description: This function digs into a zone BE's vfstab and updates all
1967 1999 * entries with file systems listed in be_fs_list_data_t.
1968 2000 * The entry's root container dataset and be_name will be
1969 2001 * updated with the parameters passed in.
1970 2002 * Parameters:
1971 2003 * zhp - zfs_handle_t pointer to zone root dataset.
1972 2004 * be_name - name of zone BE to update
1973 2005 * old_rc_loc - dataset under which the root container dataset
1974 2006 * of the old zone BE resides in.
1975 2007 * new_rc_loc - dataset under which the root container dataset
1976 2008 * of the new zone BE resides in.
1977 2009 * fld - be_fs_list_data_t pointer providing the list of
1978 2010 * file systems to look for in vfstab.
1979 2011 * Returns:
1980 2012 * BE_SUCCESS - Success
1981 2013 * be_errno_t - Failure
1982 2014 * Scope:
1983 2015 * Semi-private (library wide use only)
1984 2016 */
1985 2017 int
1986 2018 be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc,
1987 2019 char *new_rc_loc, be_fs_list_data_t *fld)
1988 2020 {
1989 2021 be_mount_data_t md = { 0 };
1990 2022 be_unmount_data_t ud = { 0 };
1991 2023 char alt_vfstab[MAXPATHLEN];
1992 2024 boolean_t mounted_here = B_FALSE;
1993 2025 int ret = BE_SUCCESS;
1994 2026
1995 2027 /*
1996 2028 * If zone root not already mounted, mount it at a
1997 2029 * temporary location.
1998 2030 */
1999 2031 if (!zfs_is_mounted(zhp, &md.altroot)) {
2000 2032 /* Generate temporary mountpoint to mount zone root */
2001 2033 if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) {
2002 2034 be_print_err(gettext("be_update_zone_vfstab: "
2003 2035 "failed to make temporary mountpoint to "
2004 2036 "mount zone root\n"));
2005 2037 return (ret);
2006 2038 }
2007 2039
2008 2040 if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) {
2009 2041 be_print_err(gettext("be_update_zone_vfstab: "
2010 2042 "failed to mount zone root %s\n"),
2011 2043 zfs_get_name(zhp));
2012 2044 free(md.altroot);
2013 2045 return (BE_ERR_MOUNT_ZONEROOT);
2014 2046 }
2015 2047 mounted_here = B_TRUE;
2016 2048 }
2017 2049
2018 2050 /* Get string from vfstab in the mounted zone BE */
2019 2051 (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
2020 2052 md.altroot);
2021 2053
2022 2054 /* Update the vfstab */
2023 2055 ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
2024 2056 fld);
2025 2057
2026 2058 /* Unmount zone root if we mounted it */
2027 2059 if (mounted_here) {
2028 2060 ud.force = B_TRUE;
2029 2061
2030 2062 if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) {
2031 2063 /* Remove the temporary mountpoint */
2032 2064 (void) rmdir(md.altroot);
2033 2065 } else {
2034 2066 be_print_err(gettext("be_update_zone_vfstab: "
2035 2067 "failed to unmount zone root %s from %s\n"),
2036 2068 zfs_get_name(zhp), md.altroot);
2037 2069 if (ret == 0)
2038 2070 ret = BE_ERR_UMOUNT_ZONEROOT;
2039 2071 }
2040 2072 }
2041 2073
2042 2074 free(md.altroot);
2043 2075 return (ret);
2044 2076 }
2045 2077
2046 2078 /*
2047 2079 * Function: be_auto_snap_name
2048 2080 * Description: Generate an auto snapshot name constructed based on the
2049 2081 * current date and time. The auto snapshot name is of the form:
2050 2082 *
2051 2083 * <date>-<time>
2052 2084 *
2053 2085 * where <date> is in ISO standard format, so the resultant name
2054 2086 * is of the form:
2055 2087 *
2056 2088 * %Y-%m-%d-%H:%M:%S
2057 2089 *
2058 2090 * Parameters:
2059 2091 * None
2060 2092 * Returns:
2061 2093 * Success - pointer to auto generated snapshot name. The name
2062 2094 * is allocated in heap storage so the caller is
2063 2095 * responsible for free'ing the name.
2064 2096 * Failure - NULL
2065 2097 * Scope:
2066 2098 * Semi-private (library wide use only)
2067 2099 */
2068 2100 char *
2069 2101 be_auto_snap_name(void)
2070 2102 {
2071 2103 time_t utc_tm = NULL;
2072 2104 struct tm *gmt_tm = NULL;
2073 2105 char gmt_time_str[64];
2074 2106 char *auto_snap_name = NULL;
2075 2107
2076 2108 if (time(&utc_tm) == -1) {
2077 2109 be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2078 2110 return (NULL);
2079 2111 }
2080 2112
2081 2113 if ((gmt_tm = gmtime(&utc_tm)) == NULL) {
2082 2114 be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2083 2115 return (NULL);
2084 2116 }
2085 2117
2086 2118 (void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm);
2087 2119
2088 2120 if ((auto_snap_name = strdup(gmt_time_str)) == NULL) {
2089 2121 be_print_err(gettext("be_auto_snap_name: "
2090 2122 "memory allocation failed\n"));
2091 2123 return (NULL);
2092 2124 }
2093 2125
2094 2126 return (auto_snap_name);
2095 2127 }
2096 2128
2097 2129 /*
2098 2130 * Function: be_auto_be_name
2099 2131 * Description: Generate an auto BE name constructed based on the BE name
2100 2132 * of the original BE being cloned.
2101 2133 * Parameters:
2102 2134 * obe_name - name of the original BE being cloned.
2103 2135 * Returns:
2104 2136 * Success - pointer to auto generated BE name. The name
2105 2137 * is allocated in heap storage so the caller is
2106 2138 * responsible for free'ing the name.
2107 2139 * Failure - NULL
2108 2140 * Scope:
2109 2141 * Semi-private (library wide use only)
2110 2142 */
2111 2143 char *
2112 2144 be_auto_be_name(char *obe_name)
2113 2145 {
2114 2146 return (be_get_auto_name(obe_name, NULL, B_FALSE));
2115 2147 }
2116 2148
2117 2149 /*
2118 2150 * Function: be_auto_zone_be_name
2119 2151 * Description: Generate an auto BE name for a zone constructed based on
2120 2152 * the BE name of the original zone BE being cloned.
2121 2153 * Parameters:
2122 2154 * container_ds - container dataset for the zone.
2123 2155 * zbe_name - name of the original zone BE being cloned.
2124 2156 * Returns:
2125 2157 * Success - pointer to auto generated BE name. The name
2126 2158 * is allocated in heap storage so the caller is
2127 2159 * responsible for free'ing the name.
2128 2160 * Failure - NULL
2129 2161 * Scope:
2130 2162 * Semi-private (library wide use only)
2131 2163 */
2132 2164 char *
2133 2165 be_auto_zone_be_name(char *container_ds, char *zbe_name)
2134 2166 {
2135 2167 return (be_get_auto_name(zbe_name, container_ds, B_TRUE));
2136 2168 }
2137 2169
2138 2170 /*
2139 2171 * Function: be_valid_be_name
2140 2172 * Description: Validates a BE name.
2141 2173 * Parameters:
2142 2174 * be_name - name of BE to validate
2143 2175 * Returns:
2144 2176 * B_TRUE - be_name is valid
2145 2177 * B_FALSE - be_name is invalid
2146 2178 * Scope:
2147 2179 * Semi-private (library wide use only)
2148 2180 */
2149 2181
2150 2182 boolean_t
2151 2183 be_valid_be_name(const char *be_name)
2152 2184 {
2153 2185 const char *c = NULL;
2154 2186 struct be_defaults be_defaults;
2155 2187
2156 2188 if (be_name == NULL)
2157 2189 return (B_FALSE);
2158 2190
2159 2191 be_get_defaults(&be_defaults);
2160 2192
2161 2193 /*
2162 2194 * A BE name must not be a multi-level dataset name. We also check
2163 2195 * that it does not contain the ' ' and '%' characters. The ' ' is
2164 2196 * a valid character for datasets, however we don't allow that in a
2165 2197 * BE name. The '%' is invalid, but zfs_name_valid() allows it for
2166 2198 * internal reasons, so we explicitly check for it here.
2167 2199 */
2168 2200 c = be_name;
2169 2201 while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
2170 2202 c++;
2171 2203
2172 2204 if (*c != '\0')
2173 2205 return (B_FALSE);
2174 2206
2175 2207 /*
2176 2208 * The BE name must comply with a zfs dataset filesystem. We also
2177 2209 * verify its length to be < BE_NAME_MAX_LEN.
2178 2210 */
2179 2211 if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) ||
2180 2212 strlen(be_name) > BE_NAME_MAX_LEN)
2181 2213 return (B_FALSE);
2182 2214
2183 2215 if (be_defaults.be_deflt_bename_starts_with[0] != '\0' &&
2184 2216 strstr(be_name, be_defaults.be_deflt_bename_starts_with) == NULL) {
2185 2217 return (B_FALSE);
2186 2218 }
2187 2219
2188 2220 return (B_TRUE);
2189 2221 }
2190 2222
2191 2223 /*
2192 2224 * Function: be_valid_auto_snap_name
2193 2225 * Description: This function checks that a snapshot name is a valid auto
2194 2226 * generated snapshot name. A valid auto generated snapshot
2195 2227 * name is of the form:
2196 2228 *
2197 2229 * %Y-%m-%d-%H:%M:%S
2198 2230 *
2199 2231 * An older form of the auto generated snapshot name also
2200 2232 * included the snapshot's BE cleanup policy and a reserved
2201 2233 * field. Those names will also be verified by this function.
2202 2234 *
2203 2235 * Examples of valid auto snapshot names are:
2204 2236 *
2205 2237 * 2008-03-31-18:41:30
2206 2238 * 2008-03-31-22:17:24
2207 2239 * <policy>:-:2008:04-05-09:12:55
2208 2240 * <policy>:-:2008:04-06-15:34:12
2209 2241 *
2210 2242 * Parameters:
2211 2243 * name - name of the snapshot to be validated.
2212 2244 * Returns:
2213 2245 * B_TRUE - the name is a valid auto snapshot name.
2214 2246 * B_FALSE - the name is not a valid auto snapshot name.
2215 2247 * Scope:
2216 2248 * Semi-private (library wide use only)
2217 2249 */
2218 2250 boolean_t
2219 2251 be_valid_auto_snap_name(char *name)
2220 2252 {
2221 2253 struct tm gmt_tm;
2222 2254
2223 2255 char *policy = NULL;
2224 2256 char *reserved = NULL;
2225 2257 char *date = NULL;
2226 2258 char *c = NULL;
2227 2259
2228 2260 /* Validate the snapshot name by converting it into utc time */
2229 2261 if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL &&
2230 2262 (mktime(&gmt_tm) != -1)) {
2231 2263 return (B_TRUE);
2232 2264 }
2233 2265
2234 2266 /*
2235 2267 * Validate the snapshot name against the older form of an
2236 2268 * auto generated snapshot name.
2237 2269 */
2238 2270 policy = strdup(name);
2239 2271
2240 2272 /*
2241 2273 * Get the first field from the snapshot name,
2242 2274 * which is the BE policy
2243 2275 */
2244 2276 c = strchr(policy, ':');
2245 2277 if (c == NULL) {
2246 2278 free(policy);
2247 2279 return (B_FALSE);
2248 2280 }
2249 2281 c[0] = '\0';
2250 2282
2251 2283 /* Validate the policy name */
2252 2284 if (!valid_be_policy(policy)) {
2253 2285 free(policy);
2254 2286 return (B_FALSE);
2255 2287 }
2256 2288
2257 2289 /* Get the next field, which is the reserved field. */
2258 2290 if (c[1] == NULL || c[1] == '\0') {
2259 2291 free(policy);
2260 2292 return (B_FALSE);
2261 2293 }
2262 2294 reserved = c+1;
2263 2295 c = strchr(reserved, ':');
2264 2296 if (c == NULL) {
2265 2297 free(policy);
2266 2298 return (B_FALSE);
2267 2299 }
2268 2300 c[0] = '\0';
2269 2301
2270 2302 /* Validate the reserved field */
2271 2303 if (strcmp(reserved, "-") != 0) {
2272 2304 free(policy);
2273 2305 return (B_FALSE);
2274 2306 }
2275 2307
2276 2308 /* The remaining string should be the date field */
2277 2309 if (c[1] == NULL || c[1] == '\0') {
2278 2310 free(policy);
2279 2311 return (B_FALSE);
2280 2312 }
2281 2313 date = c+1;
2282 2314
2283 2315 /* Validate the date string by converting it into utc time */
2284 2316 if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL ||
2285 2317 (mktime(&gmt_tm) == -1)) {
2286 2318 be_print_err(gettext("be_valid_auto_snap_name: "
2287 2319 "invalid auto snapshot name\n"));
2288 2320 free(policy);
2289 2321 return (B_FALSE);
2290 2322 }
2291 2323
2292 2324 free(policy);
2293 2325 return (B_TRUE);
2294 2326 }
2295 2327
2296 2328 /*
2297 2329 * Function: be_default_policy
2298 2330 * Description: Temporary hardcoded policy support. This function returns
2299 2331 * the default policy type to be used to create a BE or a BE
2300 2332 * snapshot.
2301 2333 * Parameters:
2302 2334 * None
2303 2335 * Returns:
2304 2336 * Name of default BE policy.
2305 2337 * Scope:
2306 2338 * Semi-private (library wide use only)
2307 2339 */
2308 2340 char *
2309 2341 be_default_policy(void)
2310 2342 {
2311 2343 return (BE_PLCY_STATIC);
2312 2344 }
2313 2345
2314 2346 /*
2315 2347 * Function: valid_be_policy
2316 2348 * Description: Temporary hardcoded policy support. This function valids
2317 2349 * whether a policy is a valid known policy or not.
2318 2350 * Paramters:
2319 2351 * policy - name of policy to validate.
2320 2352 * Returns:
2321 2353 * B_TRUE - policy is a valid.
2322 2354 * B_FALSE - policy is invalid.
2323 2355 * Scope:
2324 2356 * Semi-private (library wide use only)
2325 2357 */
2326 2358 boolean_t
2327 2359 valid_be_policy(char *policy)
2328 2360 {
2329 2361 if (policy == NULL)
2330 2362 return (B_FALSE);
2331 2363
2332 2364 if (strcmp(policy, BE_PLCY_STATIC) == 0 ||
2333 2365 strcmp(policy, BE_PLCY_VOLATILE) == 0) {
2334 2366 return (B_TRUE);
2335 2367 }
2336 2368
2337 2369 return (B_FALSE);
2338 2370 }
2339 2371
2340 2372 /*
2341 2373 * Function: be_print_err
2342 2374 * Description: This function prints out error messages if do_print is
2343 2375 * set to B_TRUE or if the BE_PRINT_ERR environment variable
2344 2376 * is set to true.
2345 2377 * Paramters:
2346 2378 * prnt_str - the string we wish to print and any arguments
2347 2379 * for the format of that string.
2348 2380 * Returns:
2349 2381 * void
2350 2382 * Scope:
2351 2383 * Semi-private (library wide use only)
2352 2384 */
2353 2385 void
2354 2386 be_print_err(char *prnt_str, ...)
2355 2387 {
2356 2388 va_list ap;
2357 2389 char buf[BUFSIZ];
2358 2390 char *env_buf;
2359 2391 static boolean_t env_checked = B_FALSE;
2360 2392
2361 2393 if (!env_checked) {
2362 2394 if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) {
2363 2395 if (strcasecmp(env_buf, "true") == 0) {
2364 2396 do_print = B_TRUE;
2365 2397 }
2366 2398 }
2367 2399 env_checked = B_TRUE;
2368 2400 }
2369 2401
2370 2402 if (do_print) {
2371 2403 va_start(ap, prnt_str);
2372 2404 /* LINTED variable format specifier */
2373 2405 (void) vsnprintf(buf, BUFSIZ, prnt_str, ap);
2374 2406 (void) fputs(buf, stderr);
2375 2407 va_end(ap);
2376 2408 }
2377 2409 }
2378 2410
2379 2411 /*
2380 2412 * Function: be_find_current_be
2381 2413 * Description: Find the currently "active" BE. Fill in the
2382 2414 * passed in be_transaction_data_t reference with the
2383 2415 * active BE's data.
2384 2416 * Paramters:
2385 2417 * none
2386 2418 * Returns:
2387 2419 * BE_SUCCESS - Success
2388 2420 * be_errnot_t - Failure
2389 2421 * Scope:
2390 2422 * Semi-private (library wide use only)
2391 2423 * Notes:
2392 2424 * The caller is responsible for initializing the libzfs handle
2393 2425 * and freeing the memory used by the active be_name.
2394 2426 */
2395 2427 int
2396 2428 be_find_current_be(be_transaction_data_t *bt)
2397 2429 {
2398 2430 int zret;
2399 2431
2400 2432 if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback,
2401 2433 bt)) == 0) {
2402 2434 be_print_err(gettext("be_find_current_be: failed to "
2403 2435 "find current BE name\n"));
2404 2436 return (BE_ERR_BE_NOENT);
2405 2437 } else if (zret < 0) {
2406 2438 be_print_err(gettext("be_find_current_be: "
2407 2439 "zpool_iter failed: %s\n"),
2408 2440 libzfs_error_description(g_zfs));
2409 2441 return (zfs_err_to_be_err(g_zfs));
2410 2442 }
2411 2443
2412 2444 return (BE_SUCCESS);
2413 2445 }
2414 2446
2415 2447 /*
2416 2448 * Function: be_zpool_find_current_be_callback
2417 2449 * Description: Callback function used to iterate through all existing pools
2418 2450 * to find the BE that is the currently booted BE.
2419 2451 * Parameters:
2420 2452 * zlp - zpool_handle_t pointer to the current pool being
2421 2453 * looked at.
2422 2454 * data - be_transaction_data_t pointer.
2423 2455 * Upon successfully finding the current BE, the
2424 2456 * obe_zpool member of this parameter is set to the
2425 2457 * pool it is found in.
2426 2458 * Return:
2427 2459 * 1 - Found current BE in this pool.
2428 2460 * 0 - Did not find current BE in this pool.
↓ open down ↓ |
2152 lines elided |
↑ open up ↑ |
2429 2461 * Scope:
2430 2462 * Semi-private (library wide use only)
2431 2463 */
2432 2464 int
2433 2465 be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data)
2434 2466 {
2435 2467 be_transaction_data_t *bt = data;
2436 2468 zfs_handle_t *zhp = NULL;
2437 2469 const char *zpool = zpool_get_name(zlp);
2438 2470 char be_container_ds[MAXPATHLEN];
2471 + char *zpath = NULL;
2439 2472
2440 2473 /*
2441 2474 * Generate string for BE container dataset
2442 2475 */
2443 - be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2476 + if (getzoneid() != GLOBAL_ZONEID) {
2477 + if ((zpath = be_get_ds_from_dir("/")) != NULL) {
2478 + (void) strlcpy(be_container_ds, dirname(zpath),
2479 + sizeof (be_container_ds));
2480 + } else {
2481 + be_print_err(gettext(
2482 + "be_zpool_find_current_be_callback: "
2483 + "zone root dataset is not mounted\n"));
2484 + return (0);
2485 + }
2486 + } else {
2487 + be_make_container_ds(zpool, be_container_ds,
2488 + sizeof (be_container_ds));
2489 + }
2444 2490
2445 2491 /*
2446 2492 * Check if a BE container dataset exists in this pool.
2447 2493 */
2448 2494 if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2449 2495 zpool_close(zlp);
2450 2496 return (0);
2451 2497 }
2452 2498
2453 2499 /*
2454 2500 * Get handle to this zpool's BE container dataset.
2455 2501 */
2456 2502 if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
2457 2503 NULL) {
2458 2504 be_print_err(gettext("be_zpool_find_current_be_callback: "
2459 2505 "failed to open BE container dataset (%s)\n"),
2460 2506 be_container_ds);
2461 2507 zpool_close(zlp);
2462 2508 return (0);
2463 2509 }
2464 2510
2465 2511 /*
2466 2512 * Iterate through all potential BEs in this zpool
2467 2513 */
2468 2514 if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) {
2469 2515 /*
2470 2516 * Found current BE dataset; set obe_zpool
2471 2517 */
2472 2518 if ((bt->obe_zpool = strdup(zpool)) == NULL) {
2473 2519 be_print_err(gettext(
2474 2520 "be_zpool_find_current_be_callback: "
2475 2521 "memory allocation failed\n"));
2476 2522 ZFS_CLOSE(zhp);
2477 2523 zpool_close(zlp);
2478 2524 return (0);
2479 2525 }
2480 2526
2481 2527 ZFS_CLOSE(zhp);
2482 2528 zpool_close(zlp);
2483 2529 return (1);
2484 2530 }
2485 2531
2486 2532 ZFS_CLOSE(zhp);
2487 2533 zpool_close(zlp);
2488 2534
2489 2535 return (0);
2490 2536 }
2491 2537
2492 2538 /*
2493 2539 * Function: be_zfs_find_current_be_callback
2494 2540 * Description: Callback function used to iterate through all BEs in a
2495 2541 * pool to find the BE that is the currently booted BE.
2496 2542 * Parameters:
2497 2543 * zhp - zfs_handle_t pointer to current filesystem being checked.
2498 2544 * data - be_transaction-data_t pointer
2499 2545 * Upon successfully finding the current BE, the
2500 2546 * obe_name and obe_root_ds members of this parameter
2501 2547 * are set to the BE name and BE's root dataset
2502 2548 * respectively.
2503 2549 * Return:
2504 2550 * 1 - Found current BE.
2505 2551 * 0 - Did not find current BE.
2506 2552 * Scope:
2507 2553 * Semi-private (library wide use only)
2508 2554 */
2509 2555 int
2510 2556 be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data)
2511 2557 {
2512 2558 be_transaction_data_t *bt = data;
2513 2559 char *mp = NULL;
2514 2560
2515 2561 /*
2516 2562 * Check if dataset is mounted, and if so where.
2517 2563 */
2518 2564 if (zfs_is_mounted(zhp, &mp)) {
2519 2565 /*
2520 2566 * If mounted at root, set obe_root_ds and obe_name
2521 2567 */
2522 2568 if (mp != NULL && strcmp(mp, "/") == 0) {
2523 2569 free(mp);
2524 2570
2525 2571 if ((bt->obe_root_ds = strdup(zfs_get_name(zhp)))
2526 2572 == NULL) {
2527 2573 be_print_err(gettext(
2528 2574 "be_zfs_find_current_be_callback: "
2529 2575 "memory allocation failed\n"));
2530 2576 ZFS_CLOSE(zhp);
2531 2577 return (0);
2532 2578 }
2533 2579
2534 2580 if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
2535 2581 == NULL) {
2536 2582 be_print_err(gettext(
2537 2583 "be_zfs_find_current_be_callback: "
2538 2584 "memory allocation failed\n"));
2539 2585 ZFS_CLOSE(zhp);
2540 2586 return (0);
2541 2587 }
2542 2588
2543 2589 ZFS_CLOSE(zhp);
2544 2590 return (1);
2545 2591 }
2546 2592
2547 2593 free(mp);
2548 2594 }
2549 2595 ZFS_CLOSE(zhp);
2550 2596
2551 2597 return (0);
2552 2598 }
2553 2599
2554 2600 /*
2555 2601 * Function: be_check_be_roots_callback
2556 2602 * Description: This function checks whether or not the dataset name passed
2557 2603 * is hierachically located under the BE root container dataset
2558 2604 * for this pool.
2559 2605 * Parameters:
2560 2606 * zlp - zpool_handle_t pointer to current pool being processed.
2561 2607 * data - name of dataset to check
2562 2608 * Returns:
2563 2609 * 0 - dataset is not in this pool's BE root container dataset
2564 2610 * 1 - dataset is in this pool's BE root container dataset
2565 2611 * Scope:
2566 2612 * Semi-private (library wide use only)
2567 2613 */
2568 2614 int
2569 2615 be_check_be_roots_callback(zpool_handle_t *zlp, void *data)
2570 2616 {
2571 2617 const char *zpool = zpool_get_name(zlp);
2572 2618 char *ds = data;
2573 2619 char be_container_ds[MAXPATHLEN];
2574 2620
2575 2621 /* Generate string for this pool's BE root container dataset */
2576 2622 be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2577 2623
2578 2624 /*
2579 2625 * If dataset lives under the BE root container dataset
2580 2626 * of this pool, return failure.
2581 2627 */
2582 2628 if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 &&
2583 2629 ds[strlen(be_container_ds)] == '/') {
2584 2630 zpool_close(zlp);
2585 2631 return (1);
2586 2632 }
2587 2633
2588 2634 zpool_close(zlp);
2589 2635 return (0);
2590 2636 }
2591 2637
2592 2638 /*
2593 2639 * Function: zfs_err_to_be_err
2594 2640 * Description: This function takes the error stored in the libzfs handle
2595 2641 * and maps it to an be_errno_t. If there are no matching
2596 2642 * be_errno_t's then BE_ERR_ZFS is returned.
2597 2643 * Paramters:
2598 2644 * zfsh - The libzfs handle containing the error we're looking up.
2599 2645 * Returns:
2600 2646 * be_errno_t
2601 2647 * Scope:
2602 2648 * Semi-private (library wide use only)
2603 2649 */
2604 2650 int
2605 2651 zfs_err_to_be_err(libzfs_handle_t *zfsh)
2606 2652 {
2607 2653 int err = libzfs_errno(zfsh);
2608 2654
2609 2655 switch (err) {
2610 2656 case 0:
2611 2657 return (BE_SUCCESS);
2612 2658 case EZFS_PERM:
2613 2659 return (BE_ERR_PERM);
2614 2660 case EZFS_INTR:
2615 2661 return (BE_ERR_INTR);
2616 2662 case EZFS_NOENT:
2617 2663 return (BE_ERR_NOENT);
2618 2664 case EZFS_NOSPC:
2619 2665 return (BE_ERR_NOSPC);
2620 2666 case EZFS_MOUNTFAILED:
2621 2667 return (BE_ERR_MOUNT);
2622 2668 case EZFS_UMOUNTFAILED:
2623 2669 return (BE_ERR_UMOUNT);
2624 2670 case EZFS_EXISTS:
2625 2671 return (BE_ERR_BE_EXISTS);
2626 2672 case EZFS_BUSY:
2627 2673 return (BE_ERR_DEV_BUSY);
2628 2674 case EZFS_POOLREADONLY:
2629 2675 return (BE_ERR_ROFS);
2630 2676 case EZFS_NAMETOOLONG:
2631 2677 return (BE_ERR_NAMETOOLONG);
2632 2678 case EZFS_NODEVICE:
2633 2679 return (BE_ERR_NODEV);
2634 2680 case EZFS_POOL_INVALARG:
2635 2681 return (BE_ERR_INVAL);
2636 2682 case EZFS_PROPTYPE:
2637 2683 return (BE_ERR_INVALPROP);
2638 2684 case EZFS_BADTYPE:
2639 2685 return (BE_ERR_DSTYPE);
2640 2686 case EZFS_PROPNONINHERIT:
2641 2687 return (BE_ERR_NONINHERIT);
2642 2688 case EZFS_PROPREADONLY:
2643 2689 return (BE_ERR_READONLYPROP);
2644 2690 case EZFS_RESILVERING:
2645 2691 case EZFS_POOLUNAVAIL:
2646 2692 return (BE_ERR_UNAVAIL);
2647 2693 case EZFS_DSREADONLY:
2648 2694 return (BE_ERR_READONLYDS);
2649 2695 default:
2650 2696 return (BE_ERR_ZFS);
2651 2697 }
2652 2698 }
2653 2699
2654 2700 /*
2655 2701 * Function: errno_to_be_err
2656 2702 * Description: This function takes an errno and maps it to an be_errno_t.
2657 2703 * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2658 2704 * returned.
2659 2705 * Paramters:
2660 2706 * err - The errno we're compairing against.
2661 2707 * Returns:
2662 2708 * be_errno_t
2663 2709 * Scope:
2664 2710 * Semi-private (library wide use only)
2665 2711 */
2666 2712 int
2667 2713 errno_to_be_err(int err)
2668 2714 {
2669 2715 switch (err) {
2670 2716 case EPERM:
2671 2717 return (BE_ERR_PERM);
2672 2718 case EACCES:
2673 2719 return (BE_ERR_ACCESS);
2674 2720 case ECANCELED:
2675 2721 return (BE_ERR_CANCELED);
2676 2722 case EINTR:
2677 2723 return (BE_ERR_INTR);
2678 2724 case ENOENT:
2679 2725 return (BE_ERR_NOENT);
2680 2726 case ENOSPC:
2681 2727 case EDQUOT:
2682 2728 return (BE_ERR_NOSPC);
2683 2729 case EEXIST:
2684 2730 return (BE_ERR_BE_EXISTS);
2685 2731 case EBUSY:
2686 2732 return (BE_ERR_BUSY);
2687 2733 case EROFS:
2688 2734 return (BE_ERR_ROFS);
2689 2735 case ENAMETOOLONG:
2690 2736 return (BE_ERR_NAMETOOLONG);
2691 2737 case ENXIO:
2692 2738 return (BE_ERR_NXIO);
2693 2739 case EINVAL:
2694 2740 return (BE_ERR_INVAL);
2695 2741 case EFAULT:
2696 2742 return (BE_ERR_FAULT);
2697 2743 default:
2698 2744 return (BE_ERR_UNKNOWN);
2699 2745 }
2700 2746 }
2701 2747
2702 2748 /*
2703 2749 * Function: be_err_to_str
2704 2750 * Description: This function takes a be_errno_t and maps it to a message.
2705 2751 * If there are no matching be_errno_t's then NULL is returned.
2706 2752 * Paramters:
2707 2753 * be_errno_t - The be_errno_t we're mapping.
2708 2754 * Returns:
2709 2755 * string or NULL if the error code is not known.
2710 2756 * Scope:
2711 2757 * Semi-private (library wide use only)
2712 2758 */
2713 2759 char *
2714 2760 be_err_to_str(int err)
2715 2761 {
2716 2762 switch (err) {
2717 2763 case BE_ERR_ACCESS:
2718 2764 return (gettext("Permission denied."));
2719 2765 case BE_ERR_ACTIVATE_CURR:
2720 2766 return (gettext("Activation of current BE failed."));
2721 2767 case BE_ERR_AUTONAME:
2722 2768 return (gettext("Auto naming failed."));
2723 2769 case BE_ERR_BE_NOENT:
2724 2770 return (gettext("No such BE."));
2725 2771 case BE_ERR_BUSY:
2726 2772 return (gettext("Mount busy."));
2727 2773 case BE_ERR_DEV_BUSY:
2728 2774 return (gettext("Device busy."));
2729 2775 case BE_ERR_CANCELED:
2730 2776 return (gettext("Operation canceled."));
2731 2777 case BE_ERR_CLONE:
2732 2778 return (gettext("BE clone failed."));
2733 2779 case BE_ERR_COPY:
2734 2780 return (gettext("BE copy failed."));
2735 2781 case BE_ERR_CREATDS:
2736 2782 return (gettext("Dataset creation failed."));
2737 2783 case BE_ERR_CURR_BE_NOT_FOUND:
2738 2784 return (gettext("Can't find current BE."));
2739 2785 case BE_ERR_DESTROY:
2740 2786 return (gettext("Failed to destroy BE or snapshot."));
2741 2787 case BE_ERR_DESTROY_CURR_BE:
2742 2788 return (gettext("Cannot destroy current BE."));
2743 2789 case BE_ERR_DEMOTE:
2744 2790 return (gettext("BE demotion failed."));
2745 2791 case BE_ERR_DSTYPE:
2746 2792 return (gettext("Invalid dataset type."));
2747 2793 case BE_ERR_BE_EXISTS:
2748 2794 return (gettext("BE exists."));
2749 2795 case BE_ERR_INIT:
2750 2796 return (gettext("be_zfs_init failed."));
2751 2797 case BE_ERR_INTR:
2752 2798 return (gettext("Interupted system call."));
2753 2799 case BE_ERR_INVAL:
2754 2800 return (gettext("Invalid argument."));
2755 2801 case BE_ERR_INVALPROP:
2756 2802 return (gettext("Invalid property for dataset."));
2757 2803 case BE_ERR_INVALMOUNTPOINT:
2758 2804 return (gettext("Unexpected mountpoint."));
2759 2805 case BE_ERR_MOUNT:
2760 2806 return (gettext("Mount failed."));
2761 2807 case BE_ERR_MOUNTED:
2762 2808 return (gettext("Already mounted."));
2763 2809 case BE_ERR_NAMETOOLONG:
2764 2810 return (gettext("name > BUFSIZ."));
2765 2811 case BE_ERR_NOENT:
2766 2812 return (gettext("Doesn't exist."));
2767 2813 case BE_ERR_POOL_NOENT:
2768 2814 return (gettext("No such pool."));
2769 2815 case BE_ERR_NODEV:
2770 2816 return (gettext("No such device."));
2771 2817 case BE_ERR_NOTMOUNTED:
2772 2818 return (gettext("File system not mounted."));
2773 2819 case BE_ERR_NOMEM:
2774 2820 return (gettext("Not enough memory."));
2775 2821 case BE_ERR_NONINHERIT:
2776 2822 return (gettext(
2777 2823 "Property is not inheritable for the BE dataset."));
2778 2824 case BE_ERR_NXIO:
2779 2825 return (gettext("No such device or address."));
2780 2826 case BE_ERR_NOSPC:
2781 2827 return (gettext("No space on device."));
2782 2828 case BE_ERR_NOTSUP:
2783 2829 return (gettext("Operation not supported."));
2784 2830 case BE_ERR_OPEN:
2785 2831 return (gettext("Open failed."));
2786 2832 case BE_ERR_PERM:
2787 2833 return (gettext("Not owner."));
2788 2834 case BE_ERR_UNAVAIL:
2789 2835 return (gettext("The BE is currently unavailable."));
2790 2836 case BE_ERR_PROMOTE:
2791 2837 return (gettext("BE promotion failed."));
2792 2838 case BE_ERR_ROFS:
2793 2839 return (gettext("Read only file system."));
2794 2840 case BE_ERR_READONLYDS:
2795 2841 return (gettext("Read only dataset."));
2796 2842 case BE_ERR_READONLYPROP:
2797 2843 return (gettext("Read only property."));
2798 2844 case BE_ERR_RENAME_ACTIVE:
2799 2845 return (gettext("Renaming the active BE is not supported."));
2800 2846 case BE_ERR_SS_EXISTS:
2801 2847 return (gettext("Snapshot exists."));
2802 2848 case BE_ERR_SS_NOENT:
2803 2849 return (gettext("No such snapshot."));
2804 2850 case BE_ERR_UMOUNT:
2805 2851 return (gettext("Unmount failed."));
2806 2852 case BE_ERR_UMOUNT_CURR_BE:
2807 2853 return (gettext("Can't unmount the current BE."));
2808 2854 case BE_ERR_UMOUNT_SHARED:
2809 2855 return (gettext("Unmount of a shared File System failed."));
2810 2856 case BE_ERR_FAULT:
2811 2857 return (gettext("Bad address."));
2812 2858 case BE_ERR_UNKNOWN:
2813 2859 return (gettext("Unknown error."));
2814 2860 case BE_ERR_ZFS:
2815 2861 return (gettext("ZFS returned an error."));
2816 2862 case BE_ERR_GEN_UUID:
2817 2863 return (gettext("Failed to generate uuid."));
2818 2864 case BE_ERR_PARSE_UUID:
2819 2865 return (gettext("Failed to parse uuid."));
2820 2866 case BE_ERR_NO_UUID:
2821 2867 return (gettext("No uuid"));
2822 2868 case BE_ERR_ZONE_NO_PARENTBE:
2823 2869 return (gettext("No parent uuid"));
2824 2870 case BE_ERR_ZONE_MULTIPLE_ACTIVE:
2825 2871 return (gettext("Multiple active zone roots"));
2826 2872 case BE_ERR_ZONE_NO_ACTIVE_ROOT:
2827 2873 return (gettext("No active zone root"));
2828 2874 case BE_ERR_ZONE_ROOT_NOT_LEGACY:
2829 2875 return (gettext("Zone root not legacy"));
2830 2876 case BE_ERR_MOUNT_ZONEROOT:
2831 2877 return (gettext("Failed to mount a zone root."));
2832 2878 case BE_ERR_UMOUNT_ZONEROOT:
2833 2879 return (gettext("Failed to unmount a zone root."));
2834 2880 case BE_ERR_NO_MOUNTED_ZONE:
2835 2881 return (gettext("Zone is not mounted"));
2836 2882 case BE_ERR_ZONES_UNMOUNT:
2837 2883 return (gettext("Unable to unmount a zone BE."));
2838 2884 case BE_ERR_NO_MENU:
2839 2885 return (gettext("Missing boot menu file."));
2840 2886 case BE_ERR_BAD_MENU_PATH:
2841 2887 return (gettext("Invalid path for menu.lst file"));
2842 2888 case BE_ERR_ZONE_SS_EXISTS:
2843 2889 return (gettext("Zone snapshot exists."));
2844 2890 case BE_ERR_BOOTFILE_INST:
2845 2891 return (gettext("Error installing boot files."));
2846 2892 case BE_ERR_EXTCMD:
2847 2893 return (gettext("Error running an external command."));
2848 2894 default:
2849 2895 return (NULL);
2850 2896 }
2851 2897 }
2852 2898
2853 2899 /*
2854 2900 * Function: be_has_grub
2855 2901 * Description: Boolean function indicating whether the current system
2856 2902 * uses grub.
2857 2903 * Return: B_FALSE - the system does not have grub
2858 2904 * B_TRUE - the system does have grub.
2859 2905 * Scope:
2860 2906 * Semi-private (library wide use only)
2861 2907 */
2862 2908 boolean_t
2863 2909 be_has_grub(void)
2864 2910 {
2865 2911 /*
2866 2912 * TODO: This will need to be expanded to check for the existence of
2867 2913 * grub if and when there is grub support for SPARC.
2868 2914 */
2869 2915 return (be_is_isa("i386"));
2870 2916 }
2871 2917
2872 2918 /*
2873 2919 * Function: be_is_isa
2874 2920 * Description: Boolean function indicating whether the instruction set
2875 2921 * architecture of the executing system matches the name provided.
2876 2922 * The string must match a system defined architecture (e.g.
2877 2923 * "i386", "sparc") and is case sensitive.
2878 2924 * Parameters: name - string representing the name of instruction set
2879 2925 * architecture being tested
2880 2926 * Returns: B_FALSE - the system instruction set architecture is different
2881 2927 * from the one specified
2882 2928 * B_TRUE - the system instruction set architecture is the same
2883 2929 * as the one specified
2884 2930 * Scope:
2885 2931 * Semi-private (library wide use only)
2886 2932 */
2887 2933 boolean_t
2888 2934 be_is_isa(char *name)
2889 2935 {
2890 2936 return ((strcmp((char *)be_get_default_isa(), name) == 0));
2891 2937 }
2892 2938
2893 2939 /*
2894 2940 * Function: be_get_default_isa
2895 2941 * Description:
2896 2942 * Returns the default instruction set architecture of the
2897 2943 * machine it is executed on. (eg. sparc, i386, ...)
2898 2944 * NOTE: SYS_INST environment variable may override default
2899 2945 * return value
2900 2946 * Parameters:
2901 2947 * none
2902 2948 * Returns:
2903 2949 * NULL - the architecture returned by sysinfo() was too
2904 2950 * long for local variables
2905 2951 * char * - pointer to a string containing the default
2906 2952 * implementation
2907 2953 * Scope:
2908 2954 * Semi-private (library wide use only)
2909 2955 */
2910 2956 char *
2911 2957 be_get_default_isa(void)
2912 2958 {
2913 2959 int i;
2914 2960 char *envp;
2915 2961 static char default_inst[ARCH_LENGTH] = "";
2916 2962
2917 2963 if (default_inst[0] == '\0') {
2918 2964 if ((envp = getenv("SYS_INST")) != NULL) {
2919 2965 if ((int)strlen(envp) >= ARCH_LENGTH)
2920 2966 return (NULL);
2921 2967 else
2922 2968 (void) strcpy(default_inst, envp);
2923 2969 } else {
2924 2970 i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH);
2925 2971 if (i < 0 || i > ARCH_LENGTH)
2926 2972 return (NULL);
2927 2973 }
2928 2974 }
2929 2975 return (default_inst);
2930 2976 }
2931 2977
2932 2978 /*
2933 2979 * Function: be_run_cmd
2934 2980 * Description:
2935 2981 * Runs a command in a separate subprocess. Splits out stdout from stderr
2936 2982 * and sends each to its own buffer. Buffers must be pre-allocated and
2937 2983 * passed in as arguments. Buffer sizes are also passed in as arguments.
2938 2984 *
2939 2985 * Notes / caveats:
2940 2986 * - Command being run is assumed to not have any stdout or stderr
2941 2987 * redirection.
2942 2988 * - Commands which emit total stderr output of greater than PIPE_BUF
2943 2989 * bytes can hang. For such commands, a different implementation
2944 2990 * which uses poll(2) must be used.
2945 2991 * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
2946 2992 * the stream which would have gone to it is sent to the bit
2947 2993 * bucket.
2948 2994 * - stderr_buf cannot be NULL.
2949 2995 * - Only subprocess errors are appended to the stderr_buf. Errors
2950 2996 * running the command are reported through be_print_err().
2951 2997 * - Data which would overflow its respective buffer is sent to the bit
2952 2998 * bucket.
2953 2999 *
2954 3000 * Parameters:
2955 3001 * command: command to run. Assumed not to have embedded stdout
2956 3002 * or stderr redirection. May have stdin redirection,
2957 3003 * however.
2958 3004 * stderr_buf: buffer returning subprocess stderr data. Errors
2959 3005 * reported by this function are reported through
2960 3006 * be_print_err().
2961 3007 * stderr_bufsize: size of stderr_buf
2962 3008 * stdout_buf: buffer returning subprocess stdout data.
2963 3009 * stdout_bufsize: size of stdout_buf
2964 3010 * Returns:
2965 3011 * BE_SUCCESS - The command ran successfully without returning
2966 3012 * errors.
2967 3013 * BE_ERR_EXTCMD
2968 3014 * - The command could not be run.
2969 3015 * - The command terminated with error status.
2970 3016 * - There were errors extracting or returning subprocess
2971 3017 * data.
2972 3018 * BE_ERR_NOMEM - The command exceeds the command buffer size.
2973 3019 * BE_ERR_INVAL - An invalid argument was specified.
2974 3020 * Scope:
2975 3021 * Semi-private (library wide use only)
2976 3022 */
2977 3023 int
2978 3024 be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize,
2979 3025 char *stdout_buf, int stdout_bufsize)
2980 3026 {
2981 3027 char *temp_filename = strdup(tmpnam(NULL));
2982 3028 FILE *stdout_str = NULL;
2983 3029 FILE *stderr_str = NULL;
2984 3030 char cmdline[BUFSIZ];
2985 3031 char oneline[BUFSIZ];
2986 3032 int exit_status;
2987 3033 int rval = BE_SUCCESS;
2988 3034
2989 3035 if ((command == NULL) || (stderr_buf == NULL) ||
2990 3036 (stderr_bufsize <= 0) || (stdout_bufsize < 0) ||
2991 3037 ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) {
2992 3038 return (BE_ERR_INVAL);
2993 3039 }
2994 3040
2995 3041 /* Set up command so popen returns stderr, not stdout */
2996 3042 if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command,
2997 3043 temp_filename) >= BUFSIZ) {
2998 3044 rval = BE_ERR_NOMEM;
2999 3045 goto cleanup;
3000 3046 }
3001 3047
3002 3048 /* Set up the fifo that will make stderr available. */
3003 3049 if (mkfifo(temp_filename, 0600) != 0) {
3004 3050 (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
3005 3051 strerror(errno));
3006 3052 rval = BE_ERR_EXTCMD;
3007 3053 goto cleanup;
3008 3054 }
3009 3055
3010 3056 if ((stdout_str = popen(cmdline, "r")) == NULL) {
3011 3057 (void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
3012 3058 strerror(errno));
3013 3059 rval = BE_ERR_EXTCMD;
3014 3060 goto cleanup;
3015 3061 }
3016 3062
3017 3063 if ((stderr_str = fopen(temp_filename, "r")) == NULL) {
3018 3064 (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
3019 3065 strerror(errno));
3020 3066 (void) pclose(stdout_str);
3021 3067 rval = BE_ERR_EXTCMD;
3022 3068 goto cleanup;
3023 3069 }
3024 3070
3025 3071 /* Read stdout first, as it usually outputs more than stderr. */
3026 3072 oneline[BUFSIZ-1] = '\0';
3027 3073 while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) {
3028 3074 if (stdout_str != NULL) {
3029 3075 (void) strlcat(stdout_buf, oneline, stdout_bufsize);
3030 3076 }
3031 3077 }
3032 3078
3033 3079 while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) {
3034 3080 (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3035 3081 }
3036 3082
3037 3083 /* Close pipe, get exit status. */
3038 3084 if ((exit_status = pclose(stdout_str)) == -1) {
3039 3085 (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
3040 3086 strerror(errno));
3041 3087 rval = BE_ERR_EXTCMD;
3042 3088 } else if (WIFEXITED(exit_status)) {
3043 3089 exit_status = (int)((char)WEXITSTATUS(exit_status));
3044 3090 if (exit_status != 0) {
3045 3091 (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: "
3046 3092 "command terminated with error status: %d\n"),
3047 3093 exit_status);
3048 3094 (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3049 3095 rval = BE_ERR_EXTCMD;
3050 3096 }
3051 3097 } else {
3052 3098 (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command "
3053 3099 "terminated on signal: %s\n"),
3054 3100 strsignal(WTERMSIG(exit_status)));
3055 3101 (void) strlcat(stderr_buf, oneline, stderr_bufsize);
3056 3102 rval = BE_ERR_EXTCMD;
3057 3103 }
3058 3104
3059 3105 cleanup:
3060 3106 (void) unlink(temp_filename);
3061 3107 (void) free(temp_filename);
3062 3108
3063 3109 return (rval);
3064 3110 }
3065 3111
3066 3112 /* ******************************************************************** */
3067 3113 /* Private Functions */
3068 3114 /* ******************************************************************** */
3069 3115
3070 3116 /*
3071 3117 * Function: update_dataset
3072 3118 * Description: This function takes a dataset name and replaces the zpool
3073 3119 * and be_name components of the dataset with the new be_name
3074 3120 * zpool passed in.
3075 3121 * Parameters:
3076 3122 * dataset - name of dataset
3077 3123 * dataset_len - lenth of buffer in which dataset is passed in.
3078 3124 * be_name - name of new BE name to update to.
3079 3125 * old_rc_loc - dataset under which the root container dataset
3080 3126 * for the old BE lives.
3081 3127 * new_rc_loc - dataset under which the root container dataset
3082 3128 * for the new BE lives.
3083 3129 * Returns:
3084 3130 * BE_SUCCESS - Success
3085 3131 * be_errno_t - Failure
3086 3132 * Scope:
3087 3133 * Private
3088 3134 */
3089 3135 static int
3090 3136 update_dataset(char *dataset, int dataset_len, char *be_name,
3091 3137 char *old_rc_loc, char *new_rc_loc)
3092 3138 {
3093 3139 char *ds = NULL;
3094 3140 char *sub_ds = NULL;
3095 3141
3096 3142 /* Tear off the BE container dataset */
3097 3143 if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) {
3098 3144 return (BE_ERR_INVAL);
3099 3145 }
3100 3146
3101 3147 /* Get dataset name relative to BE root, if there is one */
3102 3148 sub_ds = strchr(ds, '/');
3103 3149
3104 3150 /* Generate the BE root dataset name */
3105 3151 be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len);
3106 3152
3107 3153 /* If a subordinate dataset name was found, append it */
3108 3154 if (sub_ds != NULL)
3109 3155 (void) strlcat(dataset, sub_ds, dataset_len);
3110 3156
3111 3157 free(ds);
3112 3158 return (BE_SUCCESS);
3113 3159 }
3114 3160
3115 3161 /*
3116 3162 * Function: _update_vfstab
3117 3163 * Description: This function updates a vfstab file to reflect the new
3118 3164 * root container dataset location and be_name for all
3119 3165 * entries listed in the be_fs_list_data_t structure passed in.
3120 3166 * Parameters:
3121 3167 * vfstab - vfstab file to modify
3122 3168 * be_name - name of BE to update.
3123 3169 * old_rc_loc - dataset under which the root container dataset
3124 3170 * of the old BE resides in.
3125 3171 * new_rc_loc - dataset under which the root container dataset
3126 3172 * of the new BE resides in.
3127 3173 * fld - be_fs_list_data_t pointer providing the list of
3128 3174 * file systems to look for in vfstab.
3129 3175 * Returns:
3130 3176 * BE_SUCCESS - Success
3131 3177 * be_errno_t - Failure
3132 3178 * Scope:
3133 3179 * Private
3134 3180 */
3135 3181 static int
3136 3182 _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc,
3137 3183 char *new_rc_loc, be_fs_list_data_t *fld)
3138 3184 {
3139 3185 struct vfstab vp;
3140 3186 char *tmp_vfstab = NULL;
3141 3187 char comments_buf[BUFSIZ];
3142 3188 FILE *comments = NULL;
3143 3189 FILE *vfs_ents = NULL;
3144 3190 FILE *tfile = NULL;
3145 3191 struct stat sb;
3146 3192 char dev[MAXPATHLEN];
3147 3193 char *c;
3148 3194 int fd;
3149 3195 int ret = BE_SUCCESS, err = 0;
3150 3196 int i;
3151 3197 int tmp_vfstab_len = 0;
3152 3198
3153 3199 errno = 0;
3154 3200
3155 3201 /*
3156 3202 * Open vfstab for reading twice. First is for comments,
3157 3203 * second is for actual entries.
3158 3204 */
3159 3205 if ((comments = fopen(vfstab, "r")) == NULL ||
3160 3206 (vfs_ents = fopen(vfstab, "r")) == NULL) {
3161 3207 err = errno;
3162 3208 be_print_err(gettext("_update_vfstab: "
3163 3209 "failed to open vfstab (%s): %s\n"), vfstab,
3164 3210 strerror(err));
3165 3211 ret = errno_to_be_err(err);
3166 3212 goto cleanup;
3167 3213 }
3168 3214
3169 3215 /* Grab the stats of the original vfstab file */
3170 3216 if (stat(vfstab, &sb) != 0) {
3171 3217 err = errno;
3172 3218 be_print_err(gettext("_update_vfstab: "
3173 3219 "failed to stat file %s: %s\n"), vfstab,
3174 3220 strerror(err));
3175 3221 ret = errno_to_be_err(err);
3176 3222 goto cleanup;
3177 3223 }
3178 3224
3179 3225 /* Create tmp file for modified vfstab */
3180 3226 if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7))
3181 3227 == NULL) {
3182 3228 be_print_err(gettext("_update_vfstab: "
3183 3229 "malloc failed\n"));
3184 3230 ret = BE_ERR_NOMEM;
3185 3231 goto cleanup;
3186 3232 }
3187 3233 tmp_vfstab_len = strlen(vfstab) + 7;
3188 3234 (void) memset(tmp_vfstab, 0, tmp_vfstab_len);
3189 3235 (void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len);
3190 3236 (void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len);
3191 3237 if ((fd = mkstemp(tmp_vfstab)) == -1) {
3192 3238 err = errno;
3193 3239 be_print_err(gettext("_update_vfstab: "
3194 3240 "mkstemp failed: %s\n"), strerror(err));
3195 3241 ret = errno_to_be_err(err);
3196 3242 goto cleanup;
3197 3243 }
3198 3244 if ((tfile = fdopen(fd, "w")) == NULL) {
3199 3245 err = errno;
3200 3246 be_print_err(gettext("_update_vfstab: "
3201 3247 "could not open file for write\n"));
3202 3248 (void) close(fd);
3203 3249 ret = errno_to_be_err(err);
3204 3250 goto cleanup;
3205 3251 }
3206 3252
3207 3253 while (fgets(comments_buf, BUFSIZ, comments)) {
3208 3254 for (c = comments_buf; *c != '\0' && isspace(*c); c++)
3209 3255 ;
3210 3256 if (*c == '\0') {
3211 3257 continue;
3212 3258 } else if (*c == '#') {
3213 3259 /*
3214 3260 * If line is a comment line, just put
3215 3261 * it through to the tmp vfstab.
3216 3262 */
3217 3263 (void) fputs(comments_buf, tfile);
3218 3264 } else {
3219 3265 /*
3220 3266 * Else line is a vfstab entry, grab it
3221 3267 * into a vfstab struct.
3222 3268 */
3223 3269 if (getvfsent(vfs_ents, &vp) != 0) {
3224 3270 err = errno;
3225 3271 be_print_err(gettext("_update_vfstab: "
3226 3272 "getvfsent failed: %s\n"), strerror(err));
3227 3273 ret = errno_to_be_err(err);
3228 3274 goto cleanup;
3229 3275 }
3230 3276
3231 3277 if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) {
3232 3278 (void) putvfsent(tfile, &vp);
3233 3279 continue;
3234 3280 }
3235 3281
3236 3282 /*
3237 3283 * If the entry is one of the entries in the list
3238 3284 * of file systems to update, modify it's device
3239 3285 * field to be correct for this BE.
3240 3286 */
3241 3287 for (i = 0; i < fld->fs_num; i++) {
3242 3288 if (strcmp(vp.vfs_special, fld->fs_list[i])
3243 3289 == 0) {
3244 3290 /*
3245 3291 * Found entry that needs an update.
3246 3292 * Replace the root container dataset
3247 3293 * location and be_name in the
3248 3294 * entry's device.
3249 3295 */
3250 3296 (void) strlcpy(dev, vp.vfs_special,
3251 3297 sizeof (dev));
3252 3298
3253 3299 if ((ret = update_dataset(dev,
3254 3300 sizeof (dev), be_name, old_rc_loc,
3255 3301 new_rc_loc)) != 0) {
3256 3302 be_print_err(
3257 3303 gettext("_update_vfstab: "
3258 3304 "Failed to update device "
3259 3305 "field for vfstab entry "
3260 3306 "%s\n"), fld->fs_list[i]);
3261 3307 goto cleanup;
3262 3308 }
3263 3309
3264 3310 vp.vfs_special = dev;
3265 3311 break;
3266 3312 }
3267 3313 }
3268 3314
3269 3315 /* Put entry through to tmp vfstab */
3270 3316 (void) putvfsent(tfile, &vp);
3271 3317 }
3272 3318 }
3273 3319
3274 3320 (void) fclose(comments);
3275 3321 comments = NULL;
3276 3322 (void) fclose(vfs_ents);
3277 3323 vfs_ents = NULL;
3278 3324 (void) fclose(tfile);
3279 3325 tfile = NULL;
3280 3326
3281 3327 /* Copy tmp vfstab into place */
3282 3328 if (rename(tmp_vfstab, vfstab) != 0) {
3283 3329 err = errno;
3284 3330 be_print_err(gettext("_update_vfstab: "
3285 3331 "failed to rename file %s to %s: %s\n"), tmp_vfstab,
3286 3332 vfstab, strerror(err));
3287 3333 ret = errno_to_be_err(err);
3288 3334 goto cleanup;
3289 3335 }
3290 3336
3291 3337 /* Set the perms and ownership of the updated file */
3292 3338 if (chmod(vfstab, sb.st_mode) != 0) {
3293 3339 err = errno;
3294 3340 be_print_err(gettext("_update_vfstab: "
3295 3341 "failed to chmod %s: %s\n"), vfstab, strerror(err));
3296 3342 ret = errno_to_be_err(err);
3297 3343 goto cleanup;
3298 3344 }
3299 3345 if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) {
3300 3346 err = errno;
3301 3347 be_print_err(gettext("_update_vfstab: "
3302 3348 "failed to chown %s: %s\n"), vfstab, strerror(err));
3303 3349 ret = errno_to_be_err(err);
3304 3350 goto cleanup;
3305 3351 }
3306 3352
3307 3353 cleanup:
3308 3354 if (comments != NULL)
3309 3355 (void) fclose(comments);
3310 3356 if (vfs_ents != NULL)
3311 3357 (void) fclose(vfs_ents);
3312 3358 (void) unlink(tmp_vfstab);
3313 3359 (void) free(tmp_vfstab);
3314 3360 if (tfile != NULL)
3315 3361 (void) fclose(tfile);
3316 3362
3317 3363 return (ret);
3318 3364 }
3319 3365
3320 3366
3321 3367 /*
3322 3368 * Function: be_get_auto_name
3323 3369 * Description: Generate an auto name constructed based on the BE name
3324 3370 * of the original BE or zone BE being cloned.
3325 3371 * Parameters:
3326 3372 * obe_name - name of the original BE or zone BE being cloned.
3327 3373 * container_ds - container dataset for the zone.
3328 3374 * Note: if zone_be is false this should be
3329 3375 * NULL.
3330 3376 * zone_be - flag that indicates if we are operating on a zone BE.
3331 3377 * Returns:
3332 3378 * Success - pointer to auto generated BE name. The name
3333 3379 * is allocated in heap storage so the caller is
3334 3380 * responsible for free'ing the name.
3335 3381 * Failure - NULL
3336 3382 * Scope:
3337 3383 * Private
3338 3384 */
3339 3385 static char *
3340 3386 be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be)
3341 3387 {
3342 3388 be_node_list_t *be_nodes = NULL;
3343 3389 be_node_list_t *cur_be = NULL;
3344 3390 char auto_be_name[MAXPATHLEN];
3345 3391 char base_be_name[MAXPATHLEN];
3346 3392 char cur_be_name[MAXPATHLEN];
3347 3393 char *num_str = NULL;
3348 3394 char *c = NULL;
3349 3395 int num = 0;
3350 3396 int cur_num = 0;
3351 3397
3352 3398 errno = 0;
3353 3399
3354 3400 /*
3355 3401 * Check if obe_name is already in an auto BE name format.
3356 3402 * If it is, then strip off the increment number to get the
3357 3403 * base name.
3358 3404 */
3359 3405 (void) strlcpy(base_be_name, obe_name, sizeof (base_be_name));
3360 3406
3361 3407 if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM))
3362 3408 != NULL) {
3363 3409 /* Make sure remaining string is all digits */
3364 3410 c = num_str + 1;
3365 3411 while (c[0] != '\0' && isdigit(c[0]))
3366 3412 c++;
3367 3413 /*
3368 3414 * If we're now at the end of the string strip off the
3369 3415 * increment number.
3370 3416 */
3371 3417 if (c[0] == '\0')
3372 3418 num_str[0] = '\0';
3373 3419 }
3374 3420
3375 3421 if (zone_be) {
3376 3422 if (be_container_ds == NULL)
3377 3423 return (NULL);
3378 3424 if (be_get_zone_be_list(obe_name, be_container_ds,
3379 3425 &be_nodes) != BE_SUCCESS) {
3380 3426 be_print_err(gettext("be_get_auto_name: "
3381 3427 "be_get_zone_be_list failed\n"));
3382 3428 return (NULL);
3383 3429 }
3384 3430 } else if (_be_list(NULL, &be_nodes) != BE_SUCCESS) {
3385 3431 be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3386 3432 return (NULL);
3387 3433 }
3388 3434
3389 3435 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
3390 3436 (void) strlcpy(cur_be_name, cur_be->be_node_name,
3391 3437 sizeof (cur_be_name));
3392 3438
3393 3439 /* If cur_be_name doesn't match at least base be name, skip. */
3394 3440 if (strncmp(cur_be_name, base_be_name, strlen(base_be_name))
3395 3441 != 0)
3396 3442 continue;
3397 3443
3398 3444 /* Get the string following the base be name */
3399 3445 num_str = cur_be_name + strlen(base_be_name);
3400 3446
3401 3447 /*
3402 3448 * If nothing follows the base be name, this cur_be_name
3403 3449 * is the BE named with the base be name, skip.
3404 3450 */
3405 3451 if (num_str == NULL || num_str[0] == '\0')
3406 3452 continue;
3407 3453
3408 3454 /*
3409 3455 * Remove the name delimiter. If its not there,
3410 3456 * cur_be_name isn't part of this BE name stream, skip.
3411 3457 */
3412 3458 if (num_str[0] == BE_AUTO_NAME_DELIM)
3413 3459 num_str++;
3414 3460 else
3415 3461 continue;
3416 3462
3417 3463 /* Make sure remaining string is all digits */
3418 3464 c = num_str;
3419 3465 while (c[0] != '\0' && isdigit(c[0]))
3420 3466 c++;
3421 3467 if (c[0] != '\0')
3422 3468 continue;
3423 3469
3424 3470 /* Convert the number string to an int */
3425 3471 cur_num = atoi(num_str);
3426 3472
3427 3473 /*
3428 3474 * If failed to convert the string, skip it. If its too
3429 3475 * long to be converted to an int, we wouldn't auto generate
3430 3476 * this number anyway so there couldn't be a conflict.
3431 3477 * We treat it as a manually created BE name.
3432 3478 */
3433 3479 if (cur_num == 0 && errno == EINVAL)
3434 3480 continue;
3435 3481
3436 3482 /*
3437 3483 * Compare current number to current max number,
3438 3484 * take higher of the two.
3439 3485 */
3440 3486 if (cur_num > num)
3441 3487 num = cur_num;
3442 3488 }
3443 3489
3444 3490 /*
3445 3491 * Store off a copy of 'num' incase we need it later. If incrementing
3446 3492 * 'num' causes it to roll over, this means 'num' is the largest
3447 3493 * positive int possible; we'll need it later in the loop to determine
3448 3494 * if we've exhausted all possible increment numbers. We store it in
3449 3495 * 'cur_num'.
3450 3496 */
3451 3497 cur_num = num;
3452 3498
3453 3499 /* Increment 'num' to get new auto BE name number */
3454 3500 if (++num <= 0) {
3455 3501 int ret = 0;
3456 3502
3457 3503 /*
3458 3504 * Since incrementing 'num' caused it to rollover, start
3459 3505 * over at 0 and find the first available number.
3460 3506 */
3461 3507 for (num = 0; num < cur_num; num++) {
3462 3508
3463 3509 (void) snprintf(cur_be_name, sizeof (cur_be_name),
3464 3510 "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num);
3465 3511
3466 3512 ret = zpool_iter(g_zfs, be_exists_callback,
3467 3513 cur_be_name);
3468 3514
3469 3515 if (ret == 0) {
3470 3516 /*
3471 3517 * BE name doesn't exist, break out
3472 3518 * to use 'num'.
3473 3519 */
3474 3520 break;
3475 3521 } else if (ret == 1) {
3476 3522 /* BE name exists, continue looking */
3477 3523 continue;
3478 3524 } else {
3479 3525 be_print_err(gettext("be_get_auto_name: "
3480 3526 "zpool_iter failed: %s\n"),
3481 3527 libzfs_error_description(g_zfs));
3482 3528 be_free_list(be_nodes);
3483 3529 return (NULL);
3484 3530 }
3485 3531 }
3486 3532
3487 3533 /*
3488 3534 * If 'num' equals 'cur_num', we've exhausted all possible
3489 3535 * auto BE names for this base BE name.
3490 3536 */
3491 3537 if (num == cur_num) {
3492 3538 be_print_err(gettext("be_get_auto_name: "
3493 3539 "No more available auto BE names for base "
3494 3540 "BE name %s\n"), base_be_name);
3495 3541 be_free_list(be_nodes);
3496 3542 return (NULL);
3497 3543 }
3498 3544 }
3499 3545
3500 3546 be_free_list(be_nodes);
3501 3547
3502 3548 /*
3503 3549 * Generate string for auto BE name.
3504 3550 */
3505 3551 (void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d",
3506 3552 base_be_name, BE_AUTO_NAME_DELIM, num);
3507 3553
3508 3554 if ((c = strdup(auto_be_name)) == NULL) {
3509 3555 be_print_err(gettext("be_get_auto_name: "
3510 3556 "memory allocation failed\n"));
3511 3557 return (NULL);
3512 3558 }
3513 3559
3514 3560 return (c);
3515 3561 }
3516 3562
3517 3563 /*
3518 3564 * Function: be_get_console_prop
3519 3565 * Description: Determine console device.
3520 3566 * Returns:
3521 3567 * Success - pointer to console setting.
3522 3568 * Failure - NULL
3523 3569 * Scope:
3524 3570 * Private
3525 3571 */
3526 3572 static char *
3527 3573 be_get_console_prop(void)
3528 3574 {
3529 3575 di_node_t dn;
3530 3576 char *console = NULL;
3531 3577
3532 3578 if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
3533 3579 be_print_err(gettext("be_get_console_prop: "
3534 3580 "di_init() failed\n"));
3535 3581 return (NULL);
3536 3582 }
3537 3583
3538 3584 if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
3539 3585 "console", &console) != -1) {
3540 3586 di_fini(dn);
3541 3587 return (console);
3542 3588 }
3543 3589
3544 3590 if (console == NULL) {
3545 3591 if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
3546 3592 "output-device", &console) != -1) {
3547 3593 di_fini(dn);
3548 3594 if (strncmp(console, "screen", strlen("screen")) == 0)
3549 3595 console = BE_DEFAULT_CONSOLE;
3550 3596 }
3551 3597 }
3552 3598
3553 3599 /*
3554 3600 * Default console to text
3555 3601 */
3556 3602 if (console == NULL) {
3557 3603 console = BE_DEFAULT_CONSOLE;
3558 3604 }
3559 3605
3560 3606 return (console);
3561 3607 }
3562 3608
3563 3609 /*
3564 3610 * Function: be_create_menu
3565 3611 * Description:
3566 3612 * This function is used if no menu.lst file exists. In
3567 3613 * this case a new file is created and if needed default
3568 3614 * lines are added to the file.
3569 3615 * Parameters:
3570 3616 * pool - The name of the pool the menu.lst file is on
3571 3617 * menu_file - The name of the file we're creating.
3572 3618 * menu_fp - A pointer to the file pointer of the file we
3573 3619 * created. This is also used to pass back the file
3574 3620 * pointer to the newly created file.
3575 3621 * mode - the original mode used for the failed attempt to
3576 3622 * non-existent file.
3577 3623 * Returns:
3578 3624 * BE_SUCCESS - Success
3579 3625 * be_errno_t - Failure
3580 3626 * Scope:
3581 3627 * Private
3582 3628 */
3583 3629 static int
3584 3630 be_create_menu(
3585 3631 char *pool,
3586 3632 char *menu_file,
3587 3633 FILE **menu_fp,
3588 3634 char *mode)
3589 3635 {
3590 3636 be_node_list_t *be_nodes = NULL;
3591 3637 char *menu_path = NULL;
3592 3638 char *be_rpool = NULL;
3593 3639 char *be_name = NULL;
3594 3640 char *console = NULL;
3595 3641 errno = 0;
3596 3642
3597 3643 if (menu_file == NULL || menu_fp == NULL || mode == NULL)
3598 3644 return (BE_ERR_INVAL);
3599 3645
3600 3646 menu_path = strdup(menu_file);
3601 3647 if (menu_path == NULL)
3602 3648 return (BE_ERR_NOMEM);
3603 3649
3604 3650 (void) dirname(menu_path);
3605 3651 if (*menu_path == '.') {
3606 3652 free(menu_path);
3607 3653 return (BE_ERR_BAD_MENU_PATH);
3608 3654 }
3609 3655 if (mkdirp(menu_path,
3610 3656 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
3611 3657 errno != EEXIST) {
3612 3658 free(menu_path);
3613 3659 be_print_err(gettext("be_create_menu: Failed to create the %s "
3614 3660 "directory: %s\n"), menu_path, strerror(errno));
3615 3661 return (errno_to_be_err(errno));
3616 3662 }
3617 3663 free(menu_path);
3618 3664
3619 3665 /*
3620 3666 * Check to see if this system supports grub
3621 3667 */
3622 3668 if (be_has_grub()) {
3623 3669 /*
3624 3670 * The grub menu is missing so we need to create it
3625 3671 * and fill in the first few lines.
3626 3672 */
3627 3673 FILE *temp_fp = fopen(menu_file, "a+");
3628 3674 if (temp_fp == NULL) {
3629 3675 *menu_fp = NULL;
3630 3676 return (errno_to_be_err(errno));
3631 3677 }
3632 3678
3633 3679 if ((console = be_get_console_prop()) != NULL) {
3634 3680
3635 3681 /*
3636 3682 * If console is redirected to serial line,
3637 3683 * GRUB splash screen will not be enabled.
3638 3684 */
3639 3685 if (strncmp(console, "text", strlen("text")) == 0 ||
3640 3686 strncmp(console, "graphics",
3641 3687 strlen("graphics")) == 0) {
3642 3688
3643 3689 (void) fprintf(temp_fp, "%s\n", BE_GRUB_SPLASH);
3644 3690 (void) fprintf(temp_fp, "%s\n",
3645 3691 BE_GRUB_FOREGROUND);
3646 3692 (void) fprintf(temp_fp, "%s\n",
3647 3693 BE_GRUB_BACKGROUND);
3648 3694 (void) fprintf(temp_fp, "%s\n",
3649 3695 BE_GRUB_DEFAULT);
3650 3696 } else {
3651 3697 be_print_err(gettext("be_create_menu: "
3652 3698 "console on serial line, "
3653 3699 "GRUB splash image will be disabled\n"));
3654 3700 }
3655 3701 }
3656 3702
3657 3703 (void) fprintf(temp_fp, "timeout 30\n");
3658 3704 (void) fclose(temp_fp);
3659 3705
3660 3706 } else {
3661 3707 /*
3662 3708 * The menu file doesn't exist so we need to create a
3663 3709 * blank file.
3664 3710 */
3665 3711 FILE *temp_fp = fopen(menu_file, "w+");
3666 3712 if (temp_fp == NULL) {
3667 3713 *menu_fp = NULL;
3668 3714 return (errno_to_be_err(errno));
3669 3715 }
3670 3716 (void) fclose(temp_fp);
3671 3717 }
3672 3718
3673 3719 /*
3674 3720 * Now we need to add all the BE's back into the the file.
3675 3721 */
3676 3722 if (_be_list(NULL, &be_nodes) == BE_SUCCESS) {
3677 3723 while (be_nodes != NULL) {
3678 3724 if (strcmp(pool, be_nodes->be_rpool) == 0) {
3679 3725 (void) be_append_menu(be_nodes->be_node_name,
3680 3726 be_nodes->be_rpool, NULL, NULL, NULL);
3681 3727 }
3682 3728 if (be_nodes->be_active_on_boot) {
3683 3729 be_rpool = strdup(be_nodes->be_rpool);
3684 3730 be_name = strdup(be_nodes->be_node_name);
3685 3731 }
3686 3732
3687 3733 be_nodes = be_nodes->be_next_node;
3688 3734 }
3689 3735 }
3690 3736 be_free_list(be_nodes);
3691 3737
3692 3738 /*
3693 3739 * Check to see if this system supports grub
3694 3740 */
3695 3741 if (be_has_grub()) {
3696 3742 int err = be_change_grub_default(be_name, be_rpool);
3697 3743 if (err != BE_SUCCESS)
3698 3744 return (err);
3699 3745 }
3700 3746 *menu_fp = fopen(menu_file, mode);
3701 3747 if (*menu_fp == NULL)
3702 3748 return (errno_to_be_err(errno));
3703 3749
3704 3750 return (BE_SUCCESS);
3705 3751 }
3706 3752
3707 3753 /*
3708 3754 * Function: be_open_menu
3709 3755 * Description:
3710 3756 * This function is used it open the menu.lst file. If this
3711 3757 * file does not exist be_create_menu is called to create it
3712 3758 * and the open file pointer is returned. If the file does
3713 3759 * exist it is simply opened using the mode passed in.
3714 3760 * Parameters:
3715 3761 * pool - The name of the pool the menu.lst file is on
3716 3762 * menu_file - The name of the file we're opening.
3717 3763 * menu_fp - A pointer to the file pointer of the file we're
3718 3764 * opening. This is also used to pass back the file
3719 3765 * pointer.
3720 3766 * mode - the original mode to be used for opening the menu.lst
3721 3767 * file.
3722 3768 * create_menu - If this is true and the menu.lst file does not
3723 3769 * exist we will attempt to re-create it. However
3724 3770 * if it's false the error returned from the fopen
3725 3771 * will be returned.
3726 3772 * Returns:
3727 3773 * BE_SUCCESS - Success
3728 3774 * be_errno_t - Failure
3729 3775 * Scope:
3730 3776 * Private
3731 3777 */
3732 3778 static int
3733 3779 be_open_menu(
3734 3780 char *pool,
3735 3781 char *menu_file,
3736 3782 FILE **menu_fp,
3737 3783 char *mode,
3738 3784 boolean_t create_menu)
3739 3785 {
3740 3786 int err = 0;
3741 3787 boolean_t set_print = B_FALSE;
3742 3788
3743 3789 *menu_fp = fopen(menu_file, mode);
3744 3790 err = errno;
3745 3791 if (*menu_fp == NULL) {
3746 3792 if (err == ENOENT && create_menu) {
3747 3793 be_print_err(gettext("be_open_menu: menu.lst "
3748 3794 "file %s does not exist,\n"), menu_file);
3749 3795 if (!do_print) {
3750 3796 set_print = B_TRUE;
3751 3797 do_print = B_TRUE;
3752 3798 }
3753 3799 be_print_err(gettext("WARNING: menu.lst "
3754 3800 "file %s does not exist,\n generating "
3755 3801 "a new menu.lst file\n"), menu_file);
3756 3802 if (set_print)
3757 3803 do_print = B_FALSE;
3758 3804 err = 0;
3759 3805 if ((err = be_create_menu(pool, menu_file,
3760 3806 menu_fp, mode)) == ENOENT)
3761 3807 return (BE_ERR_NO_MENU);
3762 3808 else if (err != BE_SUCCESS)
3763 3809 return (err);
3764 3810 else if (*menu_fp == NULL)
3765 3811 return (BE_ERR_NO_MENU);
3766 3812 } else {
3767 3813 be_print_err(gettext("be_open_menu: failed "
3768 3814 "to open menu.lst file %s\n"), menu_file);
3769 3815 if (err == ENOENT)
3770 3816 return (BE_ERR_NO_MENU);
3771 3817 else
3772 3818 return (errno_to_be_err(err));
3773 3819 }
3774 3820 }
3775 3821 return (BE_SUCCESS);
3776 3822 }
↓ open down ↓ |
1323 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX