1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2012, Daniil Lunev. All rights reserved. 23 */ 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include "grubadm.h" 28 #include "error.h" 29 #include "menu.h" 30 31 char default_entry[MAX_STRING_SIZE] = { 0 }; 32 char timeout[MAX_STRING_SIZE] = { 0 }; 33 char serial[MAX_STRING_SIZE] = { 0 }; 34 char terminal[MAX_STRING_SIZE] = { 0 }; 35 36 const char * cmd_list[] = { 37 "entry_name", 38 "pool_label", 39 "pool_uuid", 40 "data_set", 41 "kernel_path", 42 "kernel_options", 43 "module", 44 "default_entry", 45 "timeout", 46 "serial", 47 "terminal", 48 NULL 49 }; 50 51 void 52 free_menu (menu_list ** menu) 53 { 54 unsigned int i; 55 menu_list * iter = *menu; 56 menu_list * tmp = *menu; 57 58 const char fnc[] = "free_menu"; 59 60 debug_print ("%s\n", fnc); 61 62 while (iter) { 63 if (iter->entry.modules_amount) 64 for (i = 0; i < iter->entry.modules_amount; ++i) 65 free (iter->entry.modules[i]); 66 free (iter->entry.modules); 67 tmp = iter; 68 iter = iter->next; 69 free (tmp); 70 } 71 72 *menu = NULL; 73 } 74 75 static menu_list * 76 new_entry (menu_list ** menu, const char * entry_name, const unsigned int num) 77 { 78 menu_list * added_entry; 79 menu_list * iter; 80 81 const char fnc[] = "new_entry"; 82 83 debug_print ("%s\nargs : %s | %u\n", fnc, entry_name, num); 84 85 added_entry = (menu_list *) calloc (1, sizeof (menu_list)); 86 if (! added_entry) { 87 print_system_error (); 88 return NULL; 89 } 90 91 memset ((void *) added_entry, 0, sizeof (menu_list)); 92 added_entry->entry_number = num; 93 strcpy (added_entry->entry.entry_name, entry_name); 94 added_entry->entry.modules = 95 (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *)); 96 97 if (! added_entry->entry.modules) { 98 free_menu (&added_entry); 99 print_system_error (); 100 return NULL; 101 } 102 103 if (! *menu) { 104 *menu = added_entry; 105 } else { 106 for (iter = *menu; iter->next; iter = iter->next) 107 if (! strcmp (iter->entry.entry_name, entry_name)) { 108 print_error ("%s %s", MSG_ERR_SAME_NAME, entry_name); 109 free_menu (&added_entry); 110 return NULL; 111 } 112 if (! strcmp (iter->entry.entry_name, entry_name)) { 113 print_error ("%s %s", MSG_ERR_SAME_NAME, entry_name); 114 free_menu (&added_entry); 115 return NULL; 116 } 117 iter->next = added_entry; 118 } 119 120 return added_entry; 121 } 122 123 menu_list * 124 add_entry (menu_list ** menu, menu_list * entry) 125 { 126 menu_list * iter; 127 128 const char fnc[] = "add_entry"; 129 130 debug_print ("%s\n", fnc); 131 132 if (! entry) 133 return NULL; 134 135 if (! *menu) { 136 entry->entry_number = 0; 137 *menu = entry; 138 return entry; 139 } 140 141 for (iter = * menu; iter->next; iter = iter->next) 142 if (! strcmp (iter->entry.entry_name, entry->entry.entry_name)) 143 return NULL; 144 145 if (! strcmp (iter->entry.entry_name, entry->entry.entry_name)) 146 return NULL; 147 148 iter->next = entry; 149 entry->entry_number = iter->entry_number + 1; 150 return entry; 151 } 152 153 menu_list * 154 clone_entry (menu_list * entry) 155 { 156 unsigned int i; 157 158 char fnc[] = "clone_entry"; 159 160 debug_print ("%s\n", fnc); 161 162 if (! entry) 163 return NULL; 164 menu_list * clone = (menu_list *) calloc (1, sizeof (menu_list)); 165 memcpy ((void *) clone, (void *) entry, sizeof (menu_list)); 166 clone->next = NULL; 167 clone->entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *)); 168 for (i = 0; i < clone->entry.modules_amount; ++i) 169 clone->entry.modules[i] = strdup (entry->entry.modules[i]); 170 return clone; 171 } 172 173 menu_list * 174 enable_hyper (menu_list * entry) 175 { 176 unsigned int i; 177 char kernel_mod[MAX_STRING_SIZE]; 178 179 char fnc[] = "enable_hyper"; 180 181 debug_print ("%s\n", fnc); 182 183 if (! entry) 184 return NULL; 185 186 strcpy (kernel_mod, entry->entry.kernel); 187 strcat (kernel_mod, " "); 188 strcat (kernel_mod, entry->entry.kernel); 189 strcat (kernel_mod, " "); 190 strcat (kernel_mod, entry->entry.kernel_opts); 191 192 strcpy (entry->entry.kernel, HYPER_KERNEL); 193 strcpy (entry->entry.kernel_opts, HYPER_KERNEL_OPTS); 194 195 for (i = entry->entry.modules_amount; i > 0; --i) 196 entry->entry.modules[i] = entry->entry.modules[i-1]; 197 entry->entry.modules[0] = strdup (kernel_mod); 198 ++(entry->entry.modules_amount); 199 200 return entry; 201 } 202 203 menu_list * 204 disable_hyper (menu_list * entry) 205 { 206 unsigned int i; 207 char * tmp; 208 209 char fnc[] = "disable_hyper"; 210 211 debug_print ("%s\n", fnc); 212 213 if (! entry) 214 return NULL; 215 216 tmp = strchr (entry->entry.modules[0], ' '); 217 if (! tmp) 218 return NULL; 219 220 *tmp++ = '\0'; 221 222 strcpy (entry->entry.kernel, entry->entry.modules[0]); 223 224 entry->entry.kernel_opts[0] = '\0'; 225 tmp = strchr(tmp, ' '); 226 if (tmp && *(++tmp)) { 227 strcpy (entry->entry.kernel_opts, tmp); 228 } 229 free (entry->entry.modules[0]); 230 --(entry->entry.modules_amount); 231 232 for (i = 0; i < entry->entry.modules_amount; ++i) 233 entry->entry.modules[i] = entry->entry.modules[i + 1]; 234 235 return entry; 236 } 237 238 int 239 delete_entry (menu_list ** menu, menu_list * del) 240 { 241 menu_list * iter = *menu; 242 int d_num, i_num; 243 244 const char fnc[] = "delete_entry"; 245 246 debug_print ("%s\n", fnc); 247 248 if (! menu || ! del) 249 return 0; 250 251 i_num = del->entry_number; 252 253 if (iter == del) { 254 *menu = (*menu)->next; 255 iter->next = NULL; 256 free_menu (&iter); 257 } else { 258 while (iter->next) { 259 if (iter->next == del) { 260 iter->next = del->next; 261 del->next = NULL; 262 free_menu (&del); 263 break; 264 } 265 iter = iter->next; 266 } 267 } 268 269 sscanf (default_entry, "%d", &d_num); 270 271 if (i_num <= d_num) { 272 d_num = d_num ? d_num - 1 : 0; 273 sprintf (default_entry, "%d", d_num); 274 } 275 276 return 0; 277 } 278 279 static menu_list * 280 add_param (menu_list ** menu, 281 const cmd_id id, 282 const char * value, 283 unsigned int * num) 284 { 285 menu_list * iter; 286 char * tmp; 287 288 const char fnc[] = "add_param"; 289 290 debug_print ("%s\narg: %u | %s | %u\n", fnc, (unsigned int) id, value, *num); 291 292 if (id == CMD_ENTRY_NAME) 293 return new_entry (menu, value, (*num)++); 294 295 if (! *menu) { 296 print_error ("%s, %s", MSG_ERR_WRONG_SYNTAX, "entry isn't defined"); 297 } 298 299 for (iter = * menu; iter->next; iter = iter->next) 300 ; 301 302 switch (id) { 303 case CMD_POOL_LABEL: 304 strcpy (iter->entry.pool_label, value); 305 break; 306 case CMD_POOL_UUID: 307 strcpy (iter->entry.pool_uuid, value); 308 break; 309 case CMD_DATA_SET: 310 strcpy (iter->entry.dataset, value); 311 break; 312 case CMD_KERNEL_PATH: 313 strcpy (iter->entry.kernel, value); 314 break; 315 case CMD_KERNEL_OPTIONS: 316 strcpy (iter->entry.kernel_opts, value); 317 break; 318 case CMD_BA_PATH: 319 if (iter->entry.modules_amount >= MAX_MODULE_AMOUNT) 320 return NULL; 321 iter->entry.modules[iter->entry.modules_amount] = 322 (char *) malloc (MAX_STRING_SIZE); 323 if (! iter->entry.modules[iter->entry.modules_amount]) 324 return NULL; 325 strcpy (iter->entry.modules[iter->entry.modules_amount], value); 326 ++(iter->entry.modules_amount); 327 break; 328 default: 329 return NULL; 330 } 331 return iter; 332 } 333 334 void 335 list_menu (menu_list * menu) 336 { 337 const char fnc[] = "list_menu"; 338 339 debug_print ("%s\n", fnc); 340 341 if (*default_entry) 342 printf ("%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry); 343 344 if (*timeout) 345 printf ("%s%s%s\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout); 346 347 if (*serial) 348 printf ("%s%s%s\n", cmd_list[CMD_SERIAL], SEPARATOR, serial); 349 350 if (*terminal) 351 printf ("%s%s%s\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal); 352 353 while (menu) { 354 printf("%u : %s\n", menu->entry_number, menu->entry.entry_name); 355 menu = menu->next; 356 } 357 } 358 359 menu_list * 360 find_entry (menu_list * menu, menu_list * find) 361 { 362 unsigned int i = 0; 363 const char fnc[] = "find_entry"; 364 365 debug_print ("%s\n", fnc); 366 367 if (! menu || ! find) 368 return NULL; 369 370 while (menu) { 371 if (find->entry.entry_name[0]) 372 if (strcmp (menu->entry.entry_name, find->entry.entry_name)) 373 goto out; 374 if (find->entry.pool_label[0]) 375 if (strcmp (menu->entry.pool_label, find->entry.pool_label)) 376 goto out; 377 if (find->entry.pool_uuid[0]) 378 if (strcmp (menu->entry.pool_uuid, find->entry.pool_uuid)) 379 goto out; 380 if (find->entry.dataset[0]) 381 if (strcmp (menu->entry.dataset, find->entry.dataset)) 382 goto out; 383 if (find->entry.kernel[0]) 384 if (strcmp (menu->entry.kernel, find->entry.kernel)) 385 goto out; 386 387 if (find->entry.modules_amount) { 388 for (i = 0; i < menu->entry.modules_amount; ++i) 389 if (! strcmp (menu->entry.modules[i], find->entry.modules[0])) 390 return menu; 391 goto out; 392 } 393 394 return menu; 395 out: 396 menu = menu->next; 397 } 398 399 return NULL; 400 } 401 402 menu_list * 403 get_entry_by_number (menu_list * menu, int number) 404 { 405 while (menu) 406 if (menu->entry_number == number) 407 return menu; 408 else 409 menu = menu->next; 410 return NULL; 411 } 412 413 static size_t 414 get_line (FILE * menu_file, char * line) 415 { 416 const char fnc[] = "get_line"; 417 418 debug_print ("%s\n", fnc); 419 420 if (! fgets (line, MAX_STRING_SIZE, menu_file)) { 421 if (! feof (menu_file)) 422 print_system_error (); 423 return -1; 424 } 425 426 if ((line[strlen (line) - 1] != '\n') && (! feof (menu_file))) { 427 print_error ("%s (> %d)", MSG_ERR_LONG_LINE, MAX_STRING_SIZE); 428 return -1; 429 } 430 431 line[strlen (line) - 1] = '\0'; 432 433 return strlen (line); 434 } 435 436 static cmd_id 437 get_param_id (const char * param) 438 { 439 unsigned int id; 440 441 const char fnc[] = "get_param_id"; 442 443 debug_print ("%s\narg : %s\n", fnc, param); 444 445 for (id = 0; cmd_list[id]; ++id) 446 if (! strcmp (cmd_list[id], param)) 447 break; 448 449 return id; 450 } 451 452 menu_list * 453 parse_file (const char * file_name, int * entries_amount) 454 { 455 FILE * menu_file = NULL; 456 unsigned int counter = 0; 457 menu_list * menu = NULL; 458 char line[MAX_STRING_SIZE]; 459 char * param; 460 char * value; 461 cmd_id id; 462 463 const char fnc[] = "parse_file"; 464 465 debug_print ("%s\narg : %s\n", fnc, file_name); 466 467 menu_file = fopen (file_name, "r"); 468 if (! menu_file) { 469 print_system_error (); 470 goto out; 471 } 472 473 for (;;) { 474 if (get_line (menu_file, line) == -1) { 475 if (feof (menu_file)) 476 break; 477 free_menu (&menu); 478 counter = -1; 479 goto out; 480 } 481 482 if (line[0] == '#') 483 continue; 484 485 param = line; 486 while ((*param == ' ') || (*param == '\t')) 487 ++ param; 488 if (*param == '\0') 489 continue; 490 491 value = strchr (line, '='); 492 if (! value) { 493 print_error ("%s at line '%s'", MSG_ERR_WRONG_SYNTAX, line); 494 free_menu (&menu); 495 counter = -1; 496 goto out; 497 } 498 *value++ = '\0'; 499 500 id = get_param_id (param); 501 if (id == CMD_UNKNOWN) { 502 print_error ("%s at line '%s'", MSG_ERR_WRONG_SYNTAX, line); 503 free_menu (&menu); 504 counter = -1; 505 goto out; 506 } 507 508 if (id == CMD_DEFAULT) { 509 strcpy (default_entry, value); 510 } else if (id == CMD_TIMEOUT) { 511 strcpy (timeout, value); 512 } else if (id == CMD_SERIAL) { 513 strcpy (serial, value); 514 } else if (id == CMD_TERMINAL) { 515 strcpy (terminal, value); 516 } else if (! add_param (&menu, id, value, &counter)) { 517 free_menu (&menu); 518 counter = -1; 519 goto out; 520 } 521 } 522 523 out: 524 if (menu_file) 525 fclose (menu_file); 526 527 *entries_amount = counter; 528 529 return menu; 530 } 531 532 int 533 write_menu (const char * config, const char * tmp_config, menu_list * menu) 534 { 535 FILE * tmp_menu = fopen (tmp_config, "w"); 536 unsigned int i = 0; 537 538 const char fnc[] = "write_menu"; 539 540 debug_print ("%s\n", fnc); 541 542 if (! tmp_menu) { 543 print_system_error(); 544 return 0; 545 } 546 547 if (default_entry[0]) 548 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry); 549 if (timeout[0]) 550 fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout); 551 if (serial[0]) 552 fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_SERIAL], SEPARATOR, serial); 553 if (terminal[0]) 554 fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal); 555 556 while (menu) { 557 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_ENTRY_NAME], SEPARATOR, menu->entry.entry_name); 558 if (menu->entry.pool_label[0]) 559 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_POOL_LABEL], SEPARATOR, menu->entry.pool_label); 560 if (menu->entry.pool_uuid[0]) 561 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_POOL_UUID], SEPARATOR, menu->entry.pool_uuid); 562 if (menu->entry.dataset[0]) 563 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_DATA_SET], SEPARATOR, menu->entry.dataset); 564 if (menu->entry.kernel[0]) 565 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_KERNEL_PATH], SEPARATOR, menu->entry.kernel); 566 if (menu->entry.kernel_opts[0]) 567 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_KERNEL_OPTIONS], SEPARATOR, menu->entry.kernel_opts); 568 if (menu->entry.modules_amount) 569 for (i = 0; i < menu->entry.modules_amount; ++i) 570 fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_BA_PATH], SEPARATOR, menu->entry.modules[i]); 571 fprintf (tmp_menu, "#----------------------------------------------------\n"); 572 menu = menu->next; 573 } 574 575 fclose (tmp_menu); 576 577 remove (config); 578 rename (tmp_config, config); 579 580 return 1; 581 }