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