1 1.51 martin /* $NetBSD: label.c,v 1.51 2024/02/14 13:52:11 martin Exp $ */ 2 1.1 dholland 3 1.1 dholland /* 4 1.1 dholland * Copyright 1997 Jonathan Stone 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * Redistribution and use in source and binary forms, with or without 8 1.1 dholland * modification, are permitted provided that the following conditions 9 1.1 dholland * are met: 10 1.1 dholland * 1. Redistributions of source code must retain the above copyright 11 1.1 dholland * notice, this list of conditions and the following disclaimer. 12 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer in the 14 1.1 dholland * documentation and/or other materials provided with the distribution. 15 1.1 dholland * 3. All advertising materials mentioning features or use of this software 16 1.1 dholland * must display the following acknowledgement: 17 1.1 dholland * This product includes software developed for the NetBSD Project by 18 1.1 dholland * Jonathan Stone. 19 1.1 dholland * 4. The name of Jonathan Stone may not be used to endorse 20 1.1 dholland * or promote products derived from this software without specific prior 21 1.1 dholland * written permission. 22 1.1 dholland * 23 1.1 dholland * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS'' 24 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.32 rillig * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 27 1.32 rillig * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.32 rillig * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 1.32 rillig * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 dholland * 35 1.1 dholland */ 36 1.1 dholland 37 1.1 dholland #include <sys/cdefs.h> 38 1.1 dholland #if defined(LIBC_SCCS) && !defined(lint) 39 1.51 martin __RCSID("$NetBSD: label.c,v 1.51 2024/02/14 13:52:11 martin Exp $"); 40 1.1 dholland #endif 41 1.1 dholland 42 1.1 dholland #include <sys/types.h> 43 1.1 dholland #include <stddef.h> 44 1.7 martin #include <assert.h> 45 1.1 dholland #include <errno.h> 46 1.1 dholland #include <stdio.h> 47 1.1 dholland #include <fcntl.h> 48 1.1 dholland #include <util.h> 49 1.1 dholland #include <unistd.h> 50 1.1 dholland #include <sys/dkio.h> 51 1.1 dholland #include <sys/param.h> 52 1.7 martin #include <sys/bootblock.h> 53 1.30 martin #include <sys/bitops.h> 54 1.1 dholland #include <ufs/ffs/fs.h> 55 1.1 dholland 56 1.1 dholland #include "defs.h" 57 1.1 dholland #include "msg_defs.h" 58 1.1 dholland #include "menu_defs.h" 59 1.1 dholland 60 1.1 dholland /* 61 1.1 dholland * local prototypes 62 1.1 dholland */ 63 1.7 martin static bool boringpart(const struct disk_part_info *info); 64 1.17 martin static bool checklabel(struct disk_partitions*, char *, char *); 65 1.7 martin static void show_partition_adder(menudesc *, struct partition_usage_set*); 66 1.1 dholland 67 1.1 dholland /* 68 1.7 martin * Return 1 if a partition should be ignored when checking 69 1.1 dholland * for overlapping partitions. 70 1.1 dholland */ 71 1.7 martin static bool 72 1.7 martin boringpart(const struct disk_part_info *info) 73 1.1 dholland { 74 1.1 dholland 75 1.7 martin if (info->size == 0) 76 1.7 martin return true; 77 1.48 martin if (info->flags & PTI_SPECIAL_PARTS) 78 1.7 martin return true; 79 1.7 martin 80 1.7 martin return false; 81 1.1 dholland } 82 1.1 dholland 83 1.7 martin /* 84 1.7 martin * We have some partitions in our "wanted" list that we may not edit, 85 1.7 martin * like the RAW_PART in disklabel, some that just represent external 86 1.7 martin * mount entries for the final fstab or similar. 87 1.7 martin * We have previously sorted pset->parts and pset->infos to be in sync, 88 1.7 martin * but the former "array" may be shorter. 89 1.7 martin * Here are a few quick predicates to check for them. 90 1.7 martin */ 91 1.7 martin static bool 92 1.7 martin real_partition(const struct partition_usage_set *pset, int index) 93 1.7 martin { 94 1.7 martin if (index < 0 || (size_t)index >= pset->num) 95 1.7 martin return false; 96 1.1 dholland 97 1.7 martin return pset->infos[index].cur_part_id != NO_PART; 98 1.7 martin } 99 1.1 dholland 100 1.1 dholland /* 101 1.7 martin * Check partitioning for overlapping partitions. 102 1.36 martin * Returns true if no overlapping partition found. 103 1.1 dholland * Sets reference arguments ovly1 and ovly2 to the indices of 104 1.1 dholland * overlapping partitions if any are found. 105 1.1 dholland */ 106 1.7 martin static bool 107 1.7 martin checklabel(struct disk_partitions *parts, 108 1.17 martin char *ovl1, char *ovl2) 109 1.7 martin { 110 1.7 martin part_id i, j; 111 1.7 martin struct disk_part_info info; 112 1.7 martin daddr_t istart, iend, jstart, jend; 113 1.7 martin unsigned int fs_type, fs_sub_type; 114 1.1 dholland 115 1.36 martin if (parts->num_part == 0) 116 1.36 martin return true; 117 1.36 martin 118 1.7 martin for (i = 0; i < parts->num_part - 1; i ++ ) { 119 1.7 martin if (!parts->pscheme->get_part_info(parts, i, &info)) 120 1.7 martin continue; 121 1.1 dholland 122 1.1 dholland /* skip unused or reserved partitions */ 123 1.7 martin if (boringpart(&info)) 124 1.1 dholland continue; 125 1.1 dholland 126 1.1 dholland /* 127 1.1 dholland * check succeeding partitions for overlap. 128 1.17 martin * O(n^2), but n is small. 129 1.1 dholland */ 130 1.7 martin istart = info.start; 131 1.7 martin iend = istart + info.size; 132 1.7 martin fs_type = info.fs_type; 133 1.7 martin fs_sub_type = info.fs_sub_type; 134 1.1 dholland 135 1.7 martin for (j = i+1; j < parts->num_part; j++) { 136 1.7 martin 137 1.7 martin if (!parts->pscheme->get_part_info(parts, j, &info)) 138 1.7 martin continue; 139 1.1 dholland 140 1.1 dholland /* skip unused or reserved partitions */ 141 1.7 martin if (boringpart(&info)) 142 1.1 dholland continue; 143 1.1 dholland 144 1.7 martin jstart = info.start; 145 1.7 martin jend = jstart + info.size; 146 1.1 dholland 147 1.1 dholland /* overlap? */ 148 1.7 martin if ((istart <= jstart && jstart < iend) || 149 1.7 martin (jstart <= istart && istart < jend)) { 150 1.17 martin snprintf(ovl1, MENUSTRSIZE, 151 1.7 martin "%" PRIu64 " - %" PRIu64 " %s, %s", 152 1.7 martin istart / sizemult, iend / sizemult, 153 1.7 martin multname, 154 1.7 martin getfslabelname(fs_type, fs_sub_type)); 155 1.17 martin snprintf(ovl2, MENUSTRSIZE, 156 1.7 martin "%" PRIu64 " - %" PRIu64 " %s, %s", 157 1.7 martin jstart / sizemult, jend / sizemult, 158 1.7 martin multname, 159 1.7 martin getfslabelname(info.fs_type, 160 1.7 martin info.fs_sub_type)); 161 1.7 martin return false; 162 1.1 dholland } 163 1.1 dholland } 164 1.1 dholland } 165 1.1 dholland 166 1.7 martin return true; 167 1.1 dholland } 168 1.1 dholland 169 1.2 martin int 170 1.7 martin checkoverlap(struct disk_partitions *parts) 171 1.2 martin { 172 1.7 martin char desc1[MENUSTRSIZE], desc2[MENUSTRSIZE]; 173 1.7 martin if (!checklabel(parts, desc1, desc2)) { 174 1.7 martin msg_display_subst(MSG_partitions_overlap, 2, desc1, desc2); 175 1.2 martin return 1; 176 1.2 martin } 177 1.2 martin return 0; 178 1.2 martin } 179 1.2 martin 180 1.7 martin /* 181 1.7 martin * return (see post_edit_verify): 182 1.7 martin * 0 -> abort 183 1.7 martin * 1 -> re-edit 184 1.7 martin * 2 -> continue installation 185 1.7 martin */ 186 1.1 dholland static int 187 1.18 martin verify_parts(struct partition_usage_set *pset, bool install) 188 1.1 dholland { 189 1.7 martin struct part_usage_info *wanted; 190 1.7 martin struct disk_partitions *parts; 191 1.7 martin size_t i, num_root; 192 1.28 martin daddr_t first_bsdstart, inst_start; 193 1.7 martin int rv; 194 1.7 martin 195 1.26 martin first_bsdstart = inst_start = -1; 196 1.7 martin num_root = 0; 197 1.7 martin parts = pset->parts; 198 1.7 martin for (i = 0; i < pset->num; i++) { 199 1.7 martin wanted = &pset->infos[i]; 200 1.1 dholland 201 1.7 martin if (wanted->flags & PUIFLG_JUST_MOUNTPOINT) 202 1.1 dholland continue; 203 1.7 martin if (wanted->cur_part_id == NO_PART) 204 1.7 martin continue; 205 1.7 martin if (!(wanted->instflags & PUIINST_MOUNT)) 206 1.1 dholland continue; 207 1.7 martin if (strcmp(wanted->mount, "/") != 0) 208 1.1 dholland continue; 209 1.7 martin num_root++; 210 1.32 rillig 211 1.26 martin if (first_bsdstart <= 0) { 212 1.7 martin first_bsdstart = wanted->cur_start; 213 1.7 martin } 214 1.26 martin if (inst_start < 0 && 215 1.26 martin (wanted->cur_flags & PTI_INSTALL_TARGET)) { 216 1.7 martin inst_start = wanted->cur_start; 217 1.7 martin } 218 1.7 martin } 219 1.7 martin 220 1.18 martin if ((num_root == 0 && install) || 221 1.26 martin (num_root > 1 && inst_start < 0)) { 222 1.18 martin if (num_root == 0 && install) 223 1.7 martin msg_display_subst(MSG_must_be_one_root, 2, 224 1.7 martin msg_string(parts->pscheme->name), 225 1.7 martin msg_string(parts->pscheme->short_name)); 226 1.7 martin else 227 1.7 martin msg_display_subst(MSG_multbsdpart, 2, 228 1.7 martin msg_string(parts->pscheme->name), 229 1.7 martin msg_string(parts->pscheme->short_name)); 230 1.7 martin rv = ask_reedit(parts); 231 1.7 martin if (rv != 2) 232 1.7 martin return rv; 233 1.7 martin } 234 1.7 martin 235 1.7 martin /* Check for overlaps */ 236 1.7 martin if (checkoverlap(parts) != 0) { 237 1.7 martin rv = ask_reedit(parts); 238 1.7 martin if (rv != 2) 239 1.7 martin return rv; 240 1.1 dholland } 241 1.7 martin 242 1.7 martin /* 243 1.7 martin * post_edit_verify returns: 244 1.7 martin * 0 -> abort 245 1.7 martin * 1 -> re-edit 246 1.7 martin * 2 -> continue installation 247 1.7 martin */ 248 1.7 martin if (parts->pscheme->post_edit_verify) 249 1.7 martin return parts->pscheme->post_edit_verify(parts, false); 250 1.7 martin 251 1.7 martin return 2; 252 1.1 dholland } 253 1.1 dholland 254 1.1 dholland static int 255 1.1 dholland edit_fs_start(menudesc *m, void *arg) 256 1.1 dholland { 257 1.7 martin struct single_part_fs_edit *edit = arg; 258 1.7 martin daddr_t start, end; 259 1.1 dholland 260 1.7 martin start = getpartoff(edit->pset->parts, edit->info.start); 261 1.7 martin if (edit->info.size != 0) { 262 1.39 martin if (start < (edit->info.start+edit->info.size)) { 263 1.39 martin /* Try to keep end in the same place */ 264 1.39 martin end = edit->info.start + edit->info.size; 265 1.39 martin if (end < start) 266 1.39 martin edit->info.size = edit->pset->parts->pscheme-> 267 1.39 martin max_free_space_at(edit->pset->parts, 268 1.39 martin edit->info.start); 269 1.39 martin else 270 1.39 martin edit->info.size = end - start; 271 1.39 martin } else { 272 1.39 martin edit->info.size = 0; 273 1.39 martin } 274 1.1 dholland } 275 1.7 martin edit->info.start = start; 276 1.1 dholland return 0; 277 1.1 dholland } 278 1.1 dholland 279 1.1 dholland static int 280 1.1 dholland edit_fs_size(menudesc *m, void *arg) 281 1.1 dholland { 282 1.7 martin struct single_part_fs_edit *edit = arg; 283 1.25 martin struct disk_part_info pinfo; 284 1.7 martin daddr_t size; 285 1.1 dholland 286 1.25 martin /* get original partition data, in case start moved already */ 287 1.39 martin if (!edit->pset->parts->pscheme->get_part_info(edit->pset->parts, 288 1.39 martin edit->id, &pinfo)) 289 1.39 martin pinfo = edit->info; 290 1.25 martin /* ask for new size with old start and current values */ 291 1.25 martin size = getpartsize(edit->pset->parts, pinfo.start, 292 1.25 martin edit->info.start, edit->info.size); 293 1.7 martin if (size < 0) 294 1.7 martin return 0; 295 1.7 martin if (size > edit->pset->parts->disk_size) 296 1.7 martin size = edit->pset->parts->disk_size - edit->info.start; 297 1.7 martin edit->info.size = size; 298 1.1 dholland return 0; 299 1.1 dholland } 300 1.1 dholland 301 1.7 martin static int 302 1.30 martin set_ffs_opt_pow2(menudesc *m, void *arg) 303 1.30 martin { 304 1.30 martin struct single_part_fs_edit *edit = arg; 305 1.30 martin size_t val = 1 << (edit->offset+m->cursel); 306 1.30 martin 307 1.30 martin if (edit->mode == 1) { 308 1.30 martin edit->info.fs_opt1 = val; 309 1.30 martin edit->wanted->fs_opt1 = val; 310 1.30 martin } else if (edit->mode == 2) { 311 1.30 martin edit->info.fs_opt2 = val; 312 1.30 martin edit->wanted->fs_opt2 = val; 313 1.30 martin } 314 1.30 martin return 0; 315 1.30 martin } 316 1.30 martin 317 1.30 martin static int 318 1.30 martin edit_fs_ffs_opt(menudesc *m, void *arg, msg head, 319 1.30 martin size_t min_val, size_t max_val) 320 1.30 martin { 321 1.30 martin struct single_part_fs_edit *edit = arg; 322 1.30 martin menu_ent opts[min(MAXPHYS/4096, 8)]; 323 1.30 martin char names[min(MAXPHYS/4096, 8)][20]; 324 1.30 martin size_t i, val; 325 1.30 martin int menu; 326 1.30 martin 327 1.30 martin edit->offset = ilog2(min_val); 328 1.30 martin memset(opts, 0, sizeof opts); 329 1.30 martin for (i = 0, val = min_val; val <= max_val; i++, val <<= 1) { 330 1.30 martin snprintf(names[i], sizeof names[i], "%zu", val); 331 1.30 martin opts[i].opt_name = names[i]; 332 1.30 martin opts[i].opt_action = set_ffs_opt_pow2; 333 1.30 martin opts[i].opt_flags = OPT_EXIT; 334 1.30 martin } 335 1.30 martin menu = new_menu(head, opts, i, 40, 6, 0, 0, MC_NOEXITOPT, 336 1.30 martin NULL, NULL, NULL, NULL, NULL); 337 1.30 martin if (menu < 0) 338 1.30 martin return 1; 339 1.30 martin process_menu(menu, arg); 340 1.30 martin free_menu(menu); 341 1.30 martin return 0; 342 1.30 martin } 343 1.30 martin 344 1.30 martin static int 345 1.30 martin edit_fs_ffs_block(menudesc *m, void *arg) 346 1.30 martin { 347 1.30 martin struct single_part_fs_edit *edit = arg; 348 1.30 martin 349 1.30 martin edit->mode = 1; /* edit fs_opt1 */ 350 1.30 martin return edit_fs_ffs_opt(m, arg, MSG_Select_file_system_block_size, 351 1.30 martin 4096, MAXPHYS); 352 1.30 martin } 353 1.30 martin 354 1.30 martin static int 355 1.30 martin edit_fs_ffs_frag(menudesc *m, void *arg) 356 1.30 martin { 357 1.30 martin struct single_part_fs_edit *edit = arg; 358 1.30 martin size_t bsize, sec_size; 359 1.30 martin 360 1.30 martin edit->mode = 2; /* edit fs_opt2 */ 361 1.30 martin bsize = edit->info.fs_opt1; 362 1.30 martin if (bsize == 0) { 363 1.30 martin sec_size = edit->wanted->parts->bytes_per_sector; 364 1.30 martin if (edit->wanted->size >= (daddr_t)(128L*(GIG/sec_size))) 365 1.30 martin bsize = 32*1024; 366 1.30 martin else if (edit->wanted->size >= (daddr_t)(1000L*(MEG/sec_size))) 367 1.30 martin bsize = 16*1024; 368 1.30 martin else if (edit->wanted->size >= (daddr_t)(20L*(MEG/sec_size))) 369 1.30 martin bsize = 8*1024; 370 1.30 martin else 371 1.30 martin bsize = 4+1024; 372 1.30 martin } 373 1.30 martin return edit_fs_ffs_opt(m, arg, MSG_Select_file_system_fragment_size, 374 1.30 martin bsize / 8, bsize); 375 1.30 martin } 376 1.30 martin 377 1.30 martin static int 378 1.30 martin edit_fs_ffs_avg_size(menudesc *m, void *arg) 379 1.30 martin { 380 1.30 martin struct single_part_fs_edit *edit = arg; 381 1.30 martin char answer[12]; 382 1.30 martin 383 1.30 martin snprintf(answer, sizeof answer, "%u", edit->info.fs_opt3); 384 1.30 martin msg_prompt_win(MSG_ptn_isize_prompt, -1, 18, 0, 0, 385 1.30 martin answer, answer, sizeof answer); 386 1.30 martin edit->info.fs_opt3 = atol(answer); 387 1.30 martin edit->wanted->fs_opt3 = edit->info.fs_opt3; 388 1.30 martin 389 1.30 martin return 0; 390 1.30 martin } 391 1.30 martin 392 1.30 martin static int 393 1.7 martin edit_fs_preserve(menudesc *m, void *arg) 394 1.1 dholland { 395 1.7 martin struct single_part_fs_edit *edit = arg; 396 1.1 dholland 397 1.7 martin edit->wanted->instflags ^= PUIINST_NEWFS; 398 1.7 martin return 0; 399 1.1 dholland } 400 1.1 dholland 401 1.7 martin static int 402 1.7 martin edit_install(menudesc *m, void *arg) 403 1.1 dholland { 404 1.7 martin struct single_part_fs_edit *edit = arg; 405 1.1 dholland 406 1.26 martin edit->info.flags ^= PTI_INSTALL_TARGET; 407 1.7 martin return 0; 408 1.1 dholland } 409 1.1 dholland 410 1.7 martin static int 411 1.7 martin edit_fs_mount(menudesc *m, void *arg) 412 1.1 dholland { 413 1.7 martin struct single_part_fs_edit *edit = arg; 414 1.1 dholland 415 1.7 martin edit->wanted->instflags ^= PUIINST_MOUNT; 416 1.7 martin return 0; 417 1.1 dholland } 418 1.1 dholland 419 1.1 dholland static int 420 1.7 martin edit_fs_mountpt(menudesc *m, void *arg) 421 1.1 dholland { 422 1.7 martin struct single_part_fs_edit *edit = arg; 423 1.7 martin char *p, *first, *last, buf[MOUNTLEN]; 424 1.7 martin 425 1.7 martin strlcpy(buf, edit->wanted->mount, sizeof buf); 426 1.7 martin msg_prompt_win(MSG_mountpoint, -1, 18, 0, 0, 427 1.7 martin buf, buf, MOUNTLEN); 428 1.7 martin 429 1.7 martin /* 430 1.7 martin * Trim all leading and trailing whitespace 431 1.7 martin */ 432 1.7 martin for (first = NULL, last = NULL, p = buf; *p; p++) { 433 1.7 martin if (isspace((unsigned char)*p)) 434 1.7 martin continue; 435 1.7 martin if (first == NULL) 436 1.7 martin first = p; 437 1.7 martin last = p; 438 1.7 martin } 439 1.7 martin if (last != NULL) 440 1.7 martin last[1] = 0; 441 1.7 martin 442 1.49 martin if (first == NULL || *first == 0 || strcmp(first, "-") == 0) { 443 1.7 martin edit->wanted->mount[0] = 0; 444 1.7 martin edit->wanted->instflags &= ~PUIINST_MOUNT; 445 1.7 martin return 0; 446 1.7 martin } 447 1.7 martin 448 1.7 martin if (*first != '/') { 449 1.7 martin edit->wanted->mount[0] = '/'; 450 1.7 martin strlcpy(&edit->wanted->mount[1], first, 451 1.7 martin sizeof(edit->wanted->mount)-1); 452 1.7 martin } else { 453 1.7 martin strlcpy(edit->wanted->mount, first, sizeof edit->wanted->mount); 454 1.7 martin } 455 1.49 martin edit->wanted->instflags |= PUIINST_MOUNT; 456 1.1 dholland 457 1.1 dholland return 0; 458 1.7 martin } 459 1.1 dholland 460 1.1 dholland static int 461 1.7 martin edit_restore(menudesc *m, void *arg) 462 1.1 dholland { 463 1.7 martin struct single_part_fs_edit *edit = arg; 464 1.1 dholland 465 1.7 martin edit->info = edit->old_info; 466 1.7 martin *edit->wanted = edit->old_usage; 467 1.1 dholland return 0; 468 1.1 dholland } 469 1.1 dholland 470 1.1 dholland static int 471 1.7 martin edit_cancel(menudesc *m, void *arg) 472 1.1 dholland { 473 1.7 martin struct single_part_fs_edit *edit = arg; 474 1.1 dholland 475 1.7 martin edit->rv = -1; 476 1.7 martin return 1; 477 1.1 dholland } 478 1.1 dholland 479 1.1 dholland static int 480 1.7 martin edit_delete_ptn(menudesc *m, void *arg) 481 1.1 dholland { 482 1.7 martin struct single_part_fs_edit *edit = arg; 483 1.1 dholland 484 1.7 martin edit->rv = -2; 485 1.7 martin return 1; 486 1.7 martin } 487 1.32 rillig 488 1.7 martin /* 489 1.7 martin * We have added/removed partitions, all cur_part_id values are 490 1.7 martin * out of sync. Re-fetch and reorder partitions accordingly. 491 1.7 martin */ 492 1.7 martin static void 493 1.7 martin renumber_partitions(struct partition_usage_set *pset) 494 1.7 martin { 495 1.7 martin struct part_usage_info *ninfos; 496 1.7 martin struct disk_part_info info; 497 1.7 martin size_t i; 498 1.7 martin part_id pno; 499 1.7 martin 500 1.7 martin ninfos = calloc(pset->parts->num_part, sizeof(*ninfos)); 501 1.7 martin if (ninfos == NULL) { 502 1.7 martin err_msg_win(err_outofmem); 503 1.7 martin return; 504 1.7 martin } 505 1.1 dholland 506 1.7 martin for (pno = 0; pno < pset->parts->num_part; pno++) { 507 1.7 martin if (!pset->parts->pscheme->get_part_info(pset->parts, pno, 508 1.7 martin &info)) 509 1.7 martin continue; 510 1.40 martin for (i = 0; i < pset->num; i++) { 511 1.7 martin if (pset->infos[i].cur_start != info.start) 512 1.7 martin continue; 513 1.51 martin if ((pset->infos[i].cur_flags & ~PTI_INSTALL_TARGET) 514 1.51 martin != (info.flags & ~PTI_INSTALL_TARGET)) 515 1.18 martin continue; 516 1.48 martin if ((info.flags & PTI_SPECIAL_PARTS) != 517 1.48 martin (pset->infos[i].flags & PTI_SPECIAL_PARTS)) 518 1.48 martin continue; 519 1.29 martin if ((info.fs_type != FS_UNUSED && 520 1.29 martin info.fs_type == pset->infos[i].fs_type) || 521 1.29 martin (pset->infos[i].type == 522 1.29 martin info.nat_type->generic_ptype)) { 523 1.29 martin memcpy(&ninfos[pno], &pset->infos[i], 524 1.29 martin sizeof(ninfos[pno])); 525 1.29 martin ninfos[pno].cur_part_id = pno; 526 1.29 martin break; 527 1.29 martin } 528 1.7 martin } 529 1.1 dholland } 530 1.1 dholland 531 1.40 martin free(pset->infos); 532 1.40 martin pset->infos = ninfos; 533 1.40 martin pset->num = pset->parts->num_part; 534 1.7 martin } 535 1.7 martin 536 1.7 martin /* 537 1.7 martin * Most often used file system types, we offer them in a first level menu. 538 1.7 martin */ 539 1.32 rillig static const uint edit_fs_common_types[] = 540 1.34 martin { FS_BSDFFS, FS_SWAP, FS_MSDOS, FS_EFI_SP, FS_BSDLFS, FS_EX2FS }; 541 1.7 martin 542 1.7 martin /* 543 1.7 martin * Functions for uncommon file system types - we offer the full list, 544 1.37 martin * but put FFSv2 and FFSv1 at the front and duplicate FS_MSDOS as 545 1.34 martin * EFI system partition. 546 1.7 martin */ 547 1.7 martin static void 548 1.7 martin init_fs_type_ext(menudesc *menu, void *arg) 549 1.7 martin { 550 1.7 martin struct single_part_fs_edit *edit = arg; 551 1.7 martin uint t = edit->info.fs_type; 552 1.7 martin size_t i, ndx, max = menu->numopts; 553 1.7 martin 554 1.7 martin if (t == FS_BSDFFS) { 555 1.43 martin if (edit->info.fs_sub_type == 3) 556 1.7 martin menu->cursel = 0; 557 1.43 martin else if (edit->info.fs_sub_type == 2) 558 1.43 martin menu->cursel = 1; 559 1.7 martin else 560 1.43 martin menu->cursel = 2; 561 1.7 martin return; 562 1.15 martin } else if (t == FS_EX2FS && edit->info.fs_sub_type == 1) { 563 1.43 martin menu->cursel = FSMAXTYPES+2; 564 1.15 martin return; 565 1.1 dholland } 566 1.7 martin /* skip the two FFS entries, and do not add FFS later again */ 567 1.43 martin for (ndx = 3, i = 0; i < FSMAXTYPES && ndx < max; i++) { 568 1.7 martin if (i == FS_UNUSED) 569 1.7 martin continue; 570 1.7 martin if (i == FS_BSDFFS) 571 1.7 martin continue; 572 1.7 martin if (fstypenames[i] == NULL) 573 1.7 martin continue; 574 1.1 dholland 575 1.7 martin if (i == t) { 576 1.7 martin menu->cursel = ndx; 577 1.7 martin break; 578 1.7 martin } 579 1.34 martin if (i == FS_MSDOS) { 580 1.34 martin ndx++; 581 1.34 martin if (t == FS_EFI_SP) { 582 1.34 martin menu->cursel = ndx; 583 1.34 martin break; 584 1.34 martin } 585 1.34 martin } 586 1.7 martin ndx++; 587 1.7 martin } 588 1.1 dholland } 589 1.1 dholland 590 1.1 dholland static int 591 1.7 martin set_fstype_ext(menudesc *menu, void *arg) 592 1.1 dholland { 593 1.7 martin struct single_part_fs_edit *edit = arg; 594 1.7 martin size_t i, ndx, max = menu->numopts; 595 1.16 martin enum part_type pt; 596 1.7 martin 597 1.43 martin if (menu->cursel >= 0 && menu->cursel <= 2) { 598 1.7 martin edit->info.fs_type = FS_BSDFFS; 599 1.43 martin edit->info.fs_sub_type = 3-menu->cursel; 600 1.15 martin goto found_type; 601 1.43 martin } else if (menu->cursel == FSMAXTYPES+2) { 602 1.15 martin edit->info.fs_type = FS_EX2FS; 603 1.15 martin edit->info.fs_sub_type = 1; 604 1.15 martin goto found_type; 605 1.7 martin } 606 1.1 dholland 607 1.43 martin for (ndx = 3, i = 0; i < FSMAXTYPES && ndx < max; i++) { 608 1.7 martin if (i == FS_UNUSED) 609 1.7 martin continue; 610 1.7 martin if (i == FS_BSDFFS) 611 1.7 martin continue; 612 1.7 martin if (fstypenames[i] == NULL) 613 1.7 martin continue; 614 1.7 martin 615 1.7 martin if (ndx == (size_t)menu->cursel) { 616 1.7 martin edit->info.fs_type = i; 617 1.7 martin edit->info.fs_sub_type = 0; 618 1.15 martin goto found_type; 619 1.7 martin } 620 1.7 martin ndx++; 621 1.34 martin if (i == FS_MSDOS) { 622 1.34 martin if (ndx == (size_t)menu->cursel) { 623 1.34 martin edit->info.fs_type = FS_EFI_SP; 624 1.34 martin edit->info.fs_sub_type = 0; 625 1.34 martin goto found_type; 626 1.34 martin } 627 1.43 martin ndx++; 628 1.34 martin } 629 1.7 martin } 630 1.1 dholland return 1; 631 1.15 martin 632 1.15 martin found_type: 633 1.16 martin pt = edit->info.nat_type ? edit->info.nat_type->generic_ptype : PT_root; 634 1.15 martin edit->info.nat_type = edit->pset->parts->pscheme-> 635 1.16 martin get_fs_part_type(pt, edit->info.fs_type, edit->info.fs_sub_type); 636 1.15 martin if (edit->info.nat_type == NULL) 637 1.15 martin edit->info.nat_type = edit->pset->parts->pscheme-> 638 1.15 martin get_generic_part_type(PT_root); 639 1.15 martin edit->wanted->type = edit->info.nat_type->generic_ptype; 640 1.15 martin edit->wanted->fs_type = edit->info.fs_type; 641 1.15 martin edit->wanted->fs_version = edit->info.fs_sub_type; 642 1.15 martin return 1; 643 1.1 dholland } 644 1.1 dholland 645 1.7 martin /* 646 1.7 martin * Offer a menu with "exotic" file system types, start with FFSv2 and FFSv1, 647 1.7 martin * skip later FFS entry in the generic list. 648 1.7 martin */ 649 1.1 dholland static int 650 1.7 martin edit_fs_type_ext(menudesc *menu, void *arg) 651 1.1 dholland { 652 1.7 martin menu_ent *opts; 653 1.7 martin int m; 654 1.7 martin size_t i, ndx, cnt; 655 1.7 martin 656 1.43 martin cnt = __arraycount(fstypenames)+2; 657 1.7 martin opts = calloc(cnt, sizeof(*opts)); 658 1.7 martin if (opts == NULL) 659 1.7 martin return 1; 660 1.7 martin 661 1.7 martin ndx = 0; 662 1.43 martin opts[ndx].opt_name = msg_string(MSG_fs_type_ffsv2ea); 663 1.43 martin opts[ndx].opt_action = set_fstype_ext; 664 1.43 martin ndx++; 665 1.7 martin opts[ndx].opt_name = msg_string(MSG_fs_type_ffsv2); 666 1.7 martin opts[ndx].opt_action = set_fstype_ext; 667 1.7 martin ndx++; 668 1.7 martin opts[ndx].opt_name = msg_string(MSG_fs_type_ffs); 669 1.7 martin opts[ndx].opt_action = set_fstype_ext; 670 1.7 martin ndx++; 671 1.7 martin for (i = 0; i < FSMAXTYPES && ndx < cnt; i++) { 672 1.7 martin if (i == FS_UNUSED) 673 1.7 martin continue; 674 1.7 martin if (i == FS_BSDFFS) 675 1.7 martin continue; 676 1.7 martin if (fstypenames[i] == NULL) 677 1.7 martin continue; 678 1.7 martin opts[ndx].opt_name = fstypenames[i]; 679 1.7 martin opts[ndx].opt_action = set_fstype_ext; 680 1.7 martin ndx++; 681 1.34 martin if (i == FS_MSDOS) { 682 1.34 martin opts[ndx] = opts[ndx-1]; 683 1.34 martin opts[ndx].opt_name = getfslabelname(FS_EFI_SP, 0); 684 1.34 martin ndx++; 685 1.34 martin } 686 1.7 martin } 687 1.15 martin opts[ndx].opt_name = msg_string(MSG_fs_type_ext2old); 688 1.15 martin opts[ndx].opt_action = set_fstype_ext; 689 1.15 martin ndx++; 690 1.7 martin assert(ndx == cnt); 691 1.7 martin m = new_menu(MSG_Select_the_type, opts, ndx, 692 1.7 martin 30, 6, 10, 0, MC_SUBMENU | MC_SCROLL, 693 1.7 martin init_fs_type_ext, NULL, NULL, NULL, MSG_unchanged); 694 1.7 martin 695 1.7 martin if (m < 0) 696 1.7 martin return 1; 697 1.7 martin process_menu(m, arg); 698 1.7 martin free_menu(m); 699 1.7 martin free(opts); 700 1.1 dholland 701 1.1 dholland return 1; 702 1.1 dholland } 703 1.1 dholland 704 1.1 dholland static void 705 1.7 martin init_fs_type(menudesc *menu, void *arg) 706 1.7 martin { 707 1.7 martin struct single_part_fs_edit *edit = arg; 708 1.7 martin size_t i; 709 1.7 martin 710 1.7 martin /* init menu->cursel from fs type in arg */ 711 1.7 martin if (edit->info.fs_type == FS_BSDFFS) { 712 1.43 martin if (edit->info.fs_sub_type == 3) 713 1.7 martin menu->cursel = 0; 714 1.43 martin else if (edit->info.fs_sub_type == 2) 715 1.43 martin menu->cursel = 1; 716 1.7 martin else 717 1.43 martin menu->cursel = 2; 718 1.7 martin } 719 1.7 martin for (i = 1; i < __arraycount(edit_fs_common_types); i++) { 720 1.7 martin if (edit->info.fs_type == edit_fs_common_types[i]) { 721 1.43 martin menu->cursel = i+2; 722 1.7 martin break; 723 1.7 martin } 724 1.7 martin } 725 1.7 martin } 726 1.7 martin 727 1.7 martin static int 728 1.7 martin set_fstype(menudesc *menu, void *arg) 729 1.7 martin { 730 1.7 martin struct single_part_fs_edit *edit = arg; 731 1.16 martin enum part_type pt; 732 1.7 martin int ndx; 733 1.7 martin 734 1.16 martin pt = edit->info.nat_type ? edit->info.nat_type->generic_ptype : PT_root; 735 1.43 martin if (menu->cursel < 3) { 736 1.7 martin edit->info.fs_type = FS_BSDFFS; 737 1.43 martin edit->info.fs_sub_type = 3-menu->cursel; 738 1.7 martin edit->info.nat_type = edit->pset->parts->pscheme-> 739 1.43 martin get_fs_part_type(pt, FS_BSDFFS, edit->info.fs_sub_type); 740 1.7 martin if (edit->info.nat_type == NULL) 741 1.7 martin edit->info.nat_type = edit->pset->parts-> 742 1.7 martin pscheme->get_generic_part_type(PT_root); 743 1.7 martin edit->wanted->type = edit->info.nat_type->generic_ptype; 744 1.7 martin edit->wanted->fs_type = edit->info.fs_type; 745 1.7 martin edit->wanted->fs_version = edit->info.fs_sub_type; 746 1.7 martin return 1; 747 1.7 martin } 748 1.43 martin ndx = menu->cursel-2; 749 1.7 martin 750 1.7 martin if (ndx < 0 || 751 1.7 martin (size_t)ndx >= __arraycount(edit_fs_common_types)) 752 1.7 martin return 1; 753 1.7 martin 754 1.7 martin edit->info.fs_type = edit_fs_common_types[ndx]; 755 1.7 martin edit->info.fs_sub_type = 0; 756 1.7 martin edit->info.nat_type = edit->pset->parts->pscheme-> 757 1.16 martin get_fs_part_type(pt, edit->info.fs_type, 0); 758 1.7 martin if (edit->info.nat_type == NULL) 759 1.7 martin edit->info.nat_type = edit->pset->parts-> 760 1.7 martin pscheme->get_generic_part_type(PT_root); 761 1.7 martin edit->wanted->type = edit->info.nat_type->generic_ptype; 762 1.7 martin edit->wanted->fs_type = edit->info.fs_type; 763 1.7 martin edit->wanted->fs_version = edit->info.fs_sub_type; 764 1.7 martin return 1; 765 1.7 martin } 766 1.7 martin 767 1.7 martin /* 768 1.7 martin * Offer a menu selecting the common file system types 769 1.7 martin */ 770 1.7 martin static int 771 1.7 martin edit_fs_type(menudesc *menu, void *arg) 772 1.1 dholland { 773 1.7 martin struct single_part_fs_edit *edit = arg; 774 1.7 martin menu_ent *opts; 775 1.7 martin int m, cnt; 776 1.7 martin size_t i; 777 1.7 martin 778 1.7 martin /* 779 1.7 martin * Shortcut to full menu if we have an exotic value 780 1.7 martin */ 781 1.15 martin if (edit->info.fs_type == FS_EX2FS && edit->info.fs_sub_type == 1) { 782 1.15 martin edit_fs_type_ext(menu, arg); 783 1.15 martin return 0; 784 1.15 martin } 785 1.7 martin for (i = 0; i < __arraycount(edit_fs_common_types); i++) 786 1.7 martin if (edit->info.fs_type == edit_fs_common_types[i]) 787 1.7 martin break; 788 1.7 martin if (i >= __arraycount(edit_fs_common_types)) { 789 1.7 martin edit_fs_type_ext(menu, arg); 790 1.7 martin return 0; 791 1.7 martin } 792 1.1 dholland 793 1.7 martin /* 794 1.7 martin * Starting with a common type, show short menu first 795 1.7 martin */ 796 1.43 martin cnt = __arraycount(edit_fs_common_types) + 3; 797 1.7 martin opts = calloc(cnt, sizeof(*opts)); 798 1.7 martin if (opts == NULL) 799 1.7 martin return 0; 800 1.7 martin 801 1.44 martin /* special case entry 0 - 2: three FFS entries */ 802 1.7 martin for (i = 0; i < __arraycount(edit_fs_common_types); i++) { 803 1.43 martin opts[i+2].opt_name = getfslabelname(edit_fs_common_types[i], 0); 804 1.43 martin opts[i+2].opt_action = set_fstype; 805 1.7 martin } 806 1.43 martin /* duplicate FFS (at offset 2) into first two entries */ 807 1.43 martin opts[0] = opts[1] = opts[2]; 808 1.43 martin opts[0].opt_name = msg_string(MSG_fs_type_ffsv2ea); 809 1.43 martin opts[1].opt_name = msg_string(MSG_fs_type_ffsv2); 810 1.43 martin opts[2].opt_name = msg_string(MSG_fs_type_ffs); 811 1.7 martin /* add secondary sub-menu */ 812 1.43 martin assert(i+2 < (size_t)cnt); 813 1.43 martin opts[i+2].opt_name = msg_string(MSG_other_fs_type); 814 1.43 martin opts[i+2].opt_action = edit_fs_type_ext; 815 1.7 martin 816 1.7 martin m = new_menu(MSG_Select_the_type, opts, cnt, 817 1.7 martin 30, 6, 0, 0, MC_SUBMENU | MC_SCROLL, 818 1.7 martin init_fs_type, NULL, NULL, NULL, MSG_unchanged); 819 1.7 martin 820 1.7 martin if (m < 0) 821 1.7 martin return 0; 822 1.7 martin process_menu(m, arg); 823 1.7 martin free_menu(m); 824 1.7 martin free(opts); 825 1.7 martin 826 1.7 martin return 0; 827 1.1 dholland } 828 1.1 dholland 829 1.7 martin 830 1.7 martin static void update_edit_ptn_menu(menudesc *m, void *arg); 831 1.7 martin static void draw_edit_ptn_line(menudesc *m, int opt, void *arg); 832 1.7 martin static int edit_ptn_custom_type(menudesc *m, void *arg); 833 1.1 dholland 834 1.24 martin static void 835 1.24 martin remember_deleted(struct partition_usage_set *pset, 836 1.24 martin struct disk_partitions *parts) 837 1.24 martin { 838 1.24 martin size_t i, num; 839 1.24 martin struct disk_partitions **tab; 840 1.24 martin 841 1.24 martin /* do we have parts on record already? */ 842 1.24 martin for (i = 0; i < pset->num_write_back; i++) 843 1.24 martin if (pset->write_back[i] == parts) 844 1.24 martin return; 845 1.24 martin /* 846 1.24 martin * Need to record this partition table for write back 847 1.24 martin */ 848 1.24 martin num = pset->num_write_back + 1; 849 1.24 martin tab = realloc(pset->write_back, num*sizeof(*pset->write_back)); 850 1.24 martin if (!tab) 851 1.24 martin return; 852 1.24 martin tab[pset->num_write_back] = parts; 853 1.24 martin pset->write_back = tab; 854 1.24 martin pset->num_write_back = num; 855 1.24 martin } 856 1.24 martin 857 1.2 martin int 858 1.1 dholland edit_ptn(menudesc *menu, void *arg) 859 1.1 dholland { 860 1.7 martin struct partition_usage_set *pset = arg; 861 1.7 martin struct single_part_fs_edit edit; 862 1.7 martin int fspart_menu, num_opts; 863 1.7 martin const char *err; 864 1.7 martin menu_ent *mopts, *popt; 865 1.7 martin bool is_new_part, with_inst_opt = pset->parts->parent == NULL; 866 1.7 martin 867 1.7 martin static const menu_ent edit_ptn_fields_head[] = { 868 1.8 christos { .opt_action=edit_fs_type }, 869 1.8 christos { .opt_action=edit_fs_start }, 870 1.8 christos { .opt_action=edit_fs_size }, 871 1.8 christos { .opt_flags=OPT_IGNORE }, 872 1.7 martin }; 873 1.7 martin 874 1.7 martin static const menu_ent edit_ptn_fields_head_add[] = { 875 1.8 christos { .opt_action=edit_install }, 876 1.7 martin }; 877 1.7 martin 878 1.7 martin static const menu_ent edit_ptn_fields_head2[] = { 879 1.8 christos { .opt_action=edit_fs_preserve }, 880 1.8 christos { .opt_action=edit_fs_mount }, 881 1.7 martin { .opt_menu=MENU_mountoptions, .opt_flags=OPT_SUB }, 882 1.8 christos { .opt_action=edit_fs_mountpt }, 883 1.7 martin }; 884 1.30 martin 885 1.30 martin static const menu_ent edit_ptn_fields_ffs[] = { 886 1.30 martin { .opt_action=edit_fs_ffs_avg_size }, 887 1.30 martin { .opt_action=edit_fs_ffs_block }, 888 1.30 martin { .opt_action=edit_fs_ffs_frag }, 889 1.30 martin }; 890 1.30 martin 891 1.7 martin static const menu_ent edit_ptn_fields_tail[] = { 892 1.7 martin { .opt_name=MSG_askunits, .opt_menu=MENU_sizechoice, 893 1.7 martin .opt_flags=OPT_SUB }, 894 1.8 christos { .opt_name=MSG_restore, 895 1.7 martin .opt_action=edit_restore}, 896 1.8 christos { .opt_name=MSG_Delete_partition, 897 1.7 martin .opt_action=edit_delete_ptn}, 898 1.8 christos { .opt_name=MSG_cancel, 899 1.7 martin .opt_action=edit_cancel}, 900 1.1 dholland }; 901 1.7 martin 902 1.7 martin memset(&edit, 0, sizeof edit); 903 1.7 martin edit.pset = pset; 904 1.7 martin edit.index = menu->cursel; 905 1.7 martin edit.wanted = &pset->infos[edit.index]; 906 1.7 martin 907 1.7 martin if (menu->cursel < 0 || (size_t)menu->cursel > pset->parts->num_part) 908 1.7 martin return 0; 909 1.7 martin is_new_part = (size_t)menu->cursel == pset->parts->num_part; 910 1.7 martin 911 1.7 martin num_opts = __arraycount(edit_ptn_fields_head) + 912 1.7 martin __arraycount(edit_ptn_fields_head2) + 913 1.7 martin __arraycount(edit_ptn_fields_tail); 914 1.30 martin if (edit.wanted->fs_type == FS_BSDFFS || 915 1.30 martin edit.wanted->fs_type == FS_BSDLFS) 916 1.30 martin num_opts += __arraycount(edit_ptn_fields_ffs); 917 1.7 martin if (with_inst_opt) 918 1.7 martin num_opts += __arraycount(edit_ptn_fields_head_add); 919 1.7 martin if (is_new_part) 920 1.7 martin num_opts--; 921 1.7 martin else 922 1.7 martin num_opts += pset->parts->pscheme->custom_attribute_count; 923 1.7 martin 924 1.7 martin mopts = calloc(num_opts, sizeof(*mopts)); 925 1.7 martin if (mopts == NULL) { 926 1.7 martin err_msg_win(err_outofmem); 927 1.7 martin return 0; 928 1.7 martin } 929 1.7 martin memcpy(mopts, edit_ptn_fields_head, sizeof(edit_ptn_fields_head)); 930 1.7 martin popt = mopts + __arraycount(edit_ptn_fields_head); 931 1.7 martin if (with_inst_opt) { 932 1.7 martin memcpy(popt, edit_ptn_fields_head_add, 933 1.7 martin sizeof(edit_ptn_fields_head_add)); 934 1.7 martin popt += __arraycount(edit_ptn_fields_head_add); 935 1.7 martin } 936 1.7 martin memcpy(popt, edit_ptn_fields_head2, sizeof(edit_ptn_fields_head2)); 937 1.7 martin popt += __arraycount(edit_ptn_fields_head2); 938 1.30 martin if (edit.wanted->fs_type == FS_BSDFFS || 939 1.30 martin edit.wanted->fs_type == FS_BSDLFS) { 940 1.30 martin memcpy(popt, edit_ptn_fields_ffs, sizeof(edit_ptn_fields_ffs)); 941 1.30 martin popt += __arraycount(edit_ptn_fields_ffs); 942 1.30 martin } 943 1.7 martin edit.first_custom_attr = popt - mopts; 944 1.7 martin if (!is_new_part) { 945 1.7 martin for (size_t i = 0; 946 1.7 martin i < pset->parts->pscheme->custom_attribute_count; 947 1.7 martin i++, popt++) { 948 1.7 martin popt->opt_action = edit_ptn_custom_type; 949 1.7 martin } 950 1.7 martin } 951 1.7 martin memcpy(popt, edit_ptn_fields_tail, sizeof(edit_ptn_fields_tail)); 952 1.7 martin popt += __arraycount(edit_ptn_fields_tail) - 1; 953 1.7 martin if (is_new_part) 954 1.7 martin memcpy(popt-1, popt, sizeof(*popt)); 955 1.7 martin 956 1.7 martin if (is_new_part) { 957 1.7 martin struct disk_part_free_space space; 958 1.7 martin daddr_t align = pset->parts->pscheme->get_part_alignment( 959 1.7 martin pset->parts); 960 1.7 martin 961 1.7 martin edit.id = NO_PART; 962 1.7 martin if (pset->parts->pscheme->get_free_spaces(pset->parts, 963 1.7 martin &space, 1, align, align, -1, -1) == 1) { 964 1.7 martin edit.info.start = space.start; 965 1.7 martin edit.info.size = space.size; 966 1.7 martin edit.info.fs_type = FS_BSDFFS; 967 1.7 martin edit.info.fs_sub_type = 2; 968 1.7 martin edit.info.nat_type = pset->parts->pscheme-> 969 1.16 martin get_fs_part_type(PT_root, edit.info.fs_type, 970 1.7 martin edit.info.fs_sub_type); 971 1.7 martin edit.wanted->instflags = PUIINST_NEWFS; 972 1.7 martin } 973 1.7 martin } else { 974 1.7 martin edit.id = pset->infos[edit.index].cur_part_id; 975 1.7 martin if (!pset->parts->pscheme->get_part_info(pset->parts, edit.id, 976 1.7 martin &edit.info)) { 977 1.7 martin free(mopts); 978 1.7 martin return 0; 979 1.7 martin } 980 1.7 martin } 981 1.7 martin 982 1.7 martin edit.old_usage = *edit.wanted; 983 1.7 martin edit.old_info = edit.info; 984 1.7 martin 985 1.7 martin fspart_menu = new_menu(MSG_edfspart, mopts, num_opts, 986 1.7 martin 15, 2, 0, 55, MC_NOCLEAR | MC_SCROLL, 987 1.7 martin update_edit_ptn_menu, draw_edit_ptn_line, NULL, 988 1.7 martin NULL, MSG_OK); 989 1.7 martin 990 1.7 martin process_menu(fspart_menu, &edit); 991 1.7 martin free(mopts); 992 1.7 martin free_menu(fspart_menu); 993 1.7 martin 994 1.7 martin if (edit.rv == 0) { /* OK, set new data */ 995 1.7 martin edit.info.last_mounted = edit.wanted->mount; 996 1.7 martin if (is_new_part) { 997 1.22 martin edit.wanted->parts = pset->parts; 998 1.46 martin if (!can_newfs_fstype(edit.info.fs_type)) 999 1.38 martin edit.wanted->instflags &= ~PUIINST_NEWFS; 1000 1.7 martin edit.wanted->cur_part_id = pset->parts->pscheme-> 1001 1.7 martin add_partition(pset->parts, &edit.info, &err); 1002 1.7 martin if (edit.wanted->cur_part_id == NO_PART) 1003 1.7 martin err_msg_win(err); 1004 1.7 martin else { 1005 1.7 martin pset->parts->pscheme->get_part_info( 1006 1.7 martin pset->parts, edit.wanted->cur_part_id, 1007 1.7 martin &edit.info); 1008 1.7 martin edit.wanted->cur_start = edit.info.start; 1009 1.7 martin edit.wanted->size = edit.info.size; 1010 1.7 martin edit.wanted->type = 1011 1.7 martin edit.info.nat_type->generic_ptype; 1012 1.7 martin edit.wanted->fs_type = edit.info.fs_type; 1013 1.7 martin edit.wanted->fs_version = edit.info.fs_sub_type; 1014 1.45 martin edit.wanted->cur_flags = edit.info.flags; 1015 1.7 martin /* things have changed, re-sort */ 1016 1.7 martin renumber_partitions(pset); 1017 1.7 martin } 1018 1.7 martin } else { 1019 1.7 martin if (!pset->parts->pscheme->set_part_info(pset->parts, 1020 1.7 martin edit.id, &edit.info, &err)) 1021 1.7 martin err_msg_win(err); 1022 1.41 martin else 1023 1.41 martin pset->cur_free_space += edit.old_info.size - 1024 1.41 martin edit.info.size; 1025 1.7 martin } 1026 1.7 martin 1027 1.7 martin /* 1028 1.7 martin * if size has changed, we may need to add or remove 1029 1.7 martin * the option to add partitions 1030 1.7 martin */ 1031 1.7 martin show_partition_adder(menu, pset); 1032 1.7 martin } else if (edit.rv == -1) { /* cancel edit */ 1033 1.7 martin if (is_new_part) { 1034 1.7 martin memmove(pset->infos+edit.index, 1035 1.7 martin pset->infos+edit.index+1, 1036 1.7 martin sizeof(*pset->infos)*(pset->num-edit.index)); 1037 1.7 martin memmove(menu->opts+edit.index, 1038 1.7 martin menu->opts+edit.index+1, 1039 1.7 martin sizeof(*menu->opts)*(menu->numopts-edit.index)); 1040 1.7 martin menu->numopts--; 1041 1.7 martin menu->cursel = 0; 1042 1.7 martin pset->num--; 1043 1.7 martin return -1; 1044 1.7 martin } 1045 1.7 martin pset->infos[edit.index] = edit.old_usage; 1046 1.7 martin } else if (!is_new_part && edit.rv == -2) { /* delete partition */ 1047 1.7 martin if (!pset->parts->pscheme->delete_partition(pset->parts, 1048 1.7 martin edit.id, &err)) { 1049 1.7 martin err_msg_win(err); 1050 1.7 martin return 0; 1051 1.7 martin } 1052 1.24 martin remember_deleted(pset, 1053 1.24 martin pset->infos[edit.index].parts); 1054 1.41 martin pset->cur_free_space += edit.info.size; 1055 1.7 martin memmove(pset->infos+edit.index, 1056 1.7 martin pset->infos+edit.index+1, 1057 1.7 martin sizeof(*pset->infos)*(pset->num-edit.index)); 1058 1.7 martin memmove(menu->opts+edit.index, 1059 1.7 martin menu->opts+edit.index+1, 1060 1.7 martin sizeof(*menu->opts)*(menu->numopts-edit.index)); 1061 1.7 martin menu->numopts--; 1062 1.7 martin menu->cursel = 0; 1063 1.23 martin if (pset->parts->num_part == 0) 1064 1.23 martin menu->cursel = 1; /* skip sentinel line */ 1065 1.7 martin 1066 1.7 martin /* things have changed, re-sort */ 1067 1.7 martin pset->num--; 1068 1.7 martin renumber_partitions(pset); 1069 1.7 martin 1070 1.7 martin /* we can likely add new partitions now */ 1071 1.7 martin show_partition_adder(menu, pset); 1072 1.7 martin 1073 1.7 martin return -1; 1074 1.1 dholland } 1075 1.1 dholland 1076 1.1 dholland return 0; 1077 1.1 dholland } 1078 1.1 dholland 1079 1.1 dholland static void 1080 1.7 martin update_edit_ptn_menu(menudesc *m, void *arg) 1081 1.1 dholland { 1082 1.7 martin struct single_part_fs_edit *edit = arg; 1083 1.1 dholland int i; 1084 1.7 martin uint t = edit->info.fs_type; 1085 1.7 martin size_t attr_no; 1086 1.1 dholland 1087 1.7 martin /* Determine which of the properties can be changed */ 1088 1.7 martin for (i = 0; i < m->numopts; i++) { 1089 1.7 martin if (m->opts[i].opt_action == NULL && 1090 1.7 martin m->opts[i].opt_menu != MENU_mountoptions) 1091 1.7 martin continue; 1092 1.1 dholland 1093 1.1 dholland /* Default to disabled... */ 1094 1.1 dholland m->opts[i].opt_flags |= OPT_IGNORE; 1095 1.7 martin if ((t == FS_UNUSED || t == FS_SWAP) && 1096 1.7 martin (m->opts[i].opt_action == edit_fs_preserve || 1097 1.7 martin m->opts[i].opt_action == edit_fs_mount || 1098 1.7 martin m->opts[i].opt_action == edit_fs_mountpt || 1099 1.7 martin m->opts[i].opt_menu == MENU_mountoptions)) 1100 1.1 dholland continue; 1101 1.7 martin if (m->opts[i].opt_action == edit_install && 1102 1.7 martin edit->info.nat_type && 1103 1.7 martin edit->info.nat_type->generic_ptype != PT_root) 1104 1.7 martin /* can only install onto PT_root partitions */ 1105 1.7 martin continue; 1106 1.7 martin if (m->opts[i].opt_action == edit_fs_preserve && 1107 1.38 martin !can_newfs_fstype(t)) { 1108 1.9 martin /* Can not newfs this filesystem */ 1109 1.7 martin edit->wanted->instflags &= ~PUIINST_NEWFS; 1110 1.1 dholland continue; 1111 1.1 dholland } 1112 1.7 martin if (m->opts[i].opt_action == edit_ptn_custom_type) { 1113 1.7 martin attr_no = (size_t)i - edit->first_custom_attr; 1114 1.7 martin if (!edit->pset->parts->pscheme-> 1115 1.7 martin custom_attribute_writable( 1116 1.7 martin edit->pset->parts, edit->id, attr_no)) 1117 1.1 dholland continue; 1118 1.1 dholland } 1119 1.33 martin /* 1120 1.33 martin * Do not allow editing of size/start/type when partition 1121 1.33 martin * is defined in some outer partition table already 1122 1.33 martin */ 1123 1.33 martin if ((edit->pset->infos[edit->index].flags & PUIFLG_IS_OUTER) 1124 1.33 martin && (m->opts[i].opt_action == edit_fs_type 1125 1.33 martin || m->opts[i].opt_action == edit_fs_start 1126 1.33 martin || m->opts[i].opt_action == edit_fs_size)) 1127 1.33 martin continue; 1128 1.1 dholland /* Ok: we want this one */ 1129 1.1 dholland m->opts[i].opt_flags &= ~OPT_IGNORE; 1130 1.1 dholland } 1131 1.33 martin 1132 1.33 martin /* Avoid starting at a (now) disabled menu item */ 1133 1.33 martin while (m->cursel >= 0 && m->cursel < m->numopts 1134 1.33 martin && (m->opts[m->cursel].opt_flags & OPT_IGNORE)) 1135 1.33 martin m->cursel++; 1136 1.1 dholland } 1137 1.1 dholland 1138 1.1 dholland static void 1139 1.7 martin draw_edit_ptn_line(menudesc *m, int opt, void *arg) 1140 1.1 dholland { 1141 1.7 martin struct single_part_fs_edit *edit = arg; 1142 1.7 martin static int col_width; 1143 1.7 martin static const char *ptn_type, *ptn_start, *ptn_size, *ptn_end, 1144 1.7 martin *ptn_newfs, *ptn_mount, *ptn_mount_options, *ptn_mountpt, 1145 1.30 martin *ptn_install, *ptn_bsize, *ptn_fsize, *ptn_isize; 1146 1.7 martin const char *c; 1147 1.7 martin char val[MENUSTRSIZE]; 1148 1.7 martin const char *attrname; 1149 1.7 martin size_t attr_no; 1150 1.7 martin 1151 1.7 martin if (col_width == 0) { 1152 1.7 martin int l; 1153 1.7 martin 1154 1.7 martin #define LOAD(STR) STR = msg_string(MSG_##STR); l = strlen(STR); \ 1155 1.7 martin if (l > col_width) col_width = l 1156 1.7 martin 1157 1.7 martin LOAD(ptn_type); 1158 1.7 martin LOAD(ptn_start); 1159 1.7 martin LOAD(ptn_size); 1160 1.7 martin LOAD(ptn_end); 1161 1.7 martin LOAD(ptn_install); 1162 1.7 martin LOAD(ptn_newfs); 1163 1.7 martin LOAD(ptn_mount); 1164 1.7 martin LOAD(ptn_mount_options); 1165 1.7 martin LOAD(ptn_mountpt); 1166 1.30 martin LOAD(ptn_bsize); 1167 1.30 martin LOAD(ptn_fsize); 1168 1.30 martin LOAD(ptn_isize); 1169 1.7 martin #undef LOAD 1170 1.7 martin 1171 1.7 martin for (size_t i = 0; 1172 1.7 martin i < edit->pset->parts->pscheme->custom_attribute_count; 1173 1.7 martin i++) { 1174 1.7 martin attrname = msg_string( 1175 1.7 martin edit->pset->parts->pscheme->custom_attributes[i] 1176 1.7 martin .label); 1177 1.7 martin l = strlen(attrname); 1178 1.7 martin if (l > col_width) col_width = l; 1179 1.7 martin } 1180 1.1 dholland 1181 1.7 martin col_width += 3; 1182 1.7 martin } 1183 1.1 dholland 1184 1.1 dholland if (m->opts[opt].opt_flags & OPT_IGNORE 1185 1.7 martin && (opt != 3 || edit->info.fs_type == FS_UNUSED) 1186 1.33 martin && m->opts[opt].opt_action != edit_ptn_custom_type 1187 1.33 martin && m->opts[opt].opt_action != edit_fs_type 1188 1.33 martin && m->opts[opt].opt_action != edit_fs_start 1189 1.33 martin && m->opts[opt].opt_action != edit_fs_size) { 1190 1.7 martin wprintw(m->mw, "%*s -", col_width, ""); 1191 1.1 dholland return; 1192 1.1 dholland } 1193 1.1 dholland 1194 1.7 martin if (opt < 4) { 1195 1.7 martin switch (opt) { 1196 1.7 martin case 0: 1197 1.44 martin if (edit->info.fs_type == FS_BSDFFS) { 1198 1.43 martin if (edit->info.fs_sub_type == 3) 1199 1.43 martin c = msg_string(MSG_fs_type_ffsv2ea); 1200 1.43 martin else if (edit->info.fs_sub_type == 2) 1201 1.7 martin c = msg_string(MSG_fs_type_ffsv2); 1202 1.7 martin else 1203 1.7 martin c = msg_string(MSG_fs_type_ffs); 1204 1.44 martin } else { 1205 1.7 martin c = getfslabelname(edit->info.fs_type, 1206 1.7 martin edit->info.fs_sub_type); 1207 1.44 martin } 1208 1.7 martin wprintw(m->mw, "%*s : %s", col_width, ptn_type, c); 1209 1.7 martin return; 1210 1.7 martin case 1: 1211 1.7 martin wprintw(m->mw, "%*s : %" PRIu64 " %s", col_width, 1212 1.7 martin ptn_start, edit->info.start / sizemult, multname); 1213 1.7 martin return; 1214 1.7 martin case 2: 1215 1.7 martin wprintw(m->mw, "%*s : %" PRIu64 " %s", col_width, 1216 1.7 martin ptn_size, edit->info.size / sizemult, multname); 1217 1.7 martin return; 1218 1.7 martin case 3: 1219 1.7 martin wprintw(m->mw, "%*s : %" PRIu64 " %s", col_width, 1220 1.7 martin ptn_end, (edit->info.start + edit->info.size) 1221 1.7 martin / sizemult, multname); 1222 1.7 martin return; 1223 1.7 martin } 1224 1.7 martin } 1225 1.7 martin if (m->opts[opt].opt_action == edit_install) { 1226 1.7 martin wprintw(m->mw, "%*s : %s", col_width, ptn_install, 1227 1.26 martin msg_string((edit->info.flags & PTI_INSTALL_TARGET) 1228 1.7 martin ? MSG_Yes : MSG_No)); 1229 1.7 martin return; 1230 1.7 martin } 1231 1.7 martin if (m->opts[opt].opt_action == edit_fs_preserve) { 1232 1.7 martin wprintw(m->mw, "%*s : %s", col_width, ptn_newfs, 1233 1.7 martin msg_string(edit->wanted->instflags & PUIINST_NEWFS 1234 1.7 martin ? MSG_Yes : MSG_No)); 1235 1.7 martin return; 1236 1.7 martin } 1237 1.7 martin if (m->opts[opt].opt_action == edit_fs_mount) { 1238 1.7 martin wprintw(m->mw, "%*s : %s", col_width, ptn_mount, 1239 1.7 martin msg_string(edit->wanted->instflags & PUIINST_MOUNT 1240 1.7 martin ? MSG_Yes : MSG_No)); 1241 1.7 martin return; 1242 1.7 martin } 1243 1.30 martin if (m->opts[opt].opt_action == edit_fs_ffs_block) { 1244 1.30 martin wprintw(m->mw, "%*s : %u", col_width, ptn_bsize, 1245 1.30 martin edit->wanted->fs_opt1); 1246 1.30 martin return; 1247 1.30 martin } 1248 1.30 martin if (m->opts[opt].opt_action == edit_fs_ffs_frag) { 1249 1.30 martin wprintw(m->mw, "%*s : %u", col_width, ptn_fsize, 1250 1.30 martin edit->wanted->fs_opt2); 1251 1.30 martin return; 1252 1.30 martin } 1253 1.30 martin if (m->opts[opt].opt_action == edit_fs_ffs_avg_size) { 1254 1.30 martin if (edit->wanted->fs_opt3 == 0) 1255 1.30 martin wprintw(m->mw, "%*s : %s", col_width, ptn_isize, 1256 1.30 martin msg_string(MSG_ptn_isize_dflt)); 1257 1.30 martin else { 1258 1.30 martin char buf[24], *line; 1259 1.30 martin const char *t = buf; 1260 1.30 martin 1261 1.30 martin snprintf(buf, sizeof buf, "%u", edit->wanted->fs_opt3); 1262 1.30 martin line = str_arg_subst(msg_string(MSG_ptn_isize_bytes), 1263 1.30 martin 1, &t); 1264 1.30 martin wprintw(m->mw, "%*s : %s", col_width, ptn_isize, 1265 1.30 martin line); 1266 1.30 martin free(line); 1267 1.30 martin } 1268 1.30 martin return; 1269 1.30 martin } 1270 1.7 martin if (m->opts[opt].opt_menu == MENU_mountoptions) { 1271 1.7 martin wprintw(m->mw, "%*s : ", col_width, ptn_mount_options); 1272 1.7 martin if (edit->wanted->mountflags & PUIMNT_ASYNC) 1273 1.1 dholland wprintw(m->mw, "async "); 1274 1.7 martin if (edit->wanted->mountflags & PUIMNT_NOATIME) 1275 1.1 dholland wprintw(m->mw, "noatime "); 1276 1.7 martin if (edit->wanted->mountflags & PUIMNT_NODEV) 1277 1.1 dholland wprintw(m->mw, "nodev "); 1278 1.7 martin if (edit->wanted->mountflags & PUIMNT_NODEVMTIME) 1279 1.1 dholland wprintw(m->mw, "nodevmtime "); 1280 1.7 martin if (edit->wanted->mountflags & PUIMNT_NOEXEC) 1281 1.1 dholland wprintw(m->mw, "noexec "); 1282 1.7 martin if (edit->wanted->mountflags & PUIMNT_NOSUID) 1283 1.1 dholland wprintw(m->mw, "nosuid "); 1284 1.7 martin if (edit->wanted->mountflags & PUIMNT_LOG) 1285 1.1 dholland wprintw(m->mw, "log "); 1286 1.7 martin if (edit->wanted->mountflags & PUIMNT_NOAUTO) 1287 1.7 martin wprintw(m->mw, "noauto "); 1288 1.7 martin return; 1289 1.7 martin } 1290 1.7 martin if (m->opts[opt].opt_action == edit_fs_mountpt) { 1291 1.7 martin wprintw(m->mw, "%*s : %s", col_width, ptn_mountpt, 1292 1.7 martin edit->wanted->mount); 1293 1.7 martin return; 1294 1.7 martin } 1295 1.7 martin 1296 1.7 martin attr_no = opt - edit->first_custom_attr; 1297 1.7 martin edit->pset->parts->pscheme->format_custom_attribute( 1298 1.7 martin edit->pset->parts, edit->id, attr_no, &edit->info, 1299 1.7 martin val, sizeof val); 1300 1.7 martin attrname = msg_string(edit->pset->parts->pscheme-> 1301 1.7 martin custom_attributes[attr_no].label); 1302 1.7 martin wprintw(m->mw, "%*s : %s", col_width, attrname, val); 1303 1.7 martin } 1304 1.7 martin 1305 1.7 martin static int 1306 1.7 martin edit_ptn_custom_type(menudesc *m, void *arg) 1307 1.7 martin { 1308 1.7 martin struct single_part_fs_edit *edit = arg; 1309 1.7 martin size_t attr_no = m->cursel - edit->first_custom_attr; 1310 1.7 martin char line[STRSIZE]; 1311 1.7 martin 1312 1.7 martin switch (edit->pset->parts->pscheme->custom_attributes[attr_no].type) { 1313 1.7 martin case pet_bool: 1314 1.7 martin edit->pset->parts->pscheme->custom_attribute_toggle( 1315 1.7 martin edit->pset->parts, edit->id, attr_no); 1316 1.1 dholland break; 1317 1.7 martin case pet_cardinal: 1318 1.7 martin case pet_str: 1319 1.7 martin edit->pset->parts->pscheme->format_custom_attribute( 1320 1.7 martin edit->pset->parts, edit->id, attr_no, &edit->info, 1321 1.7 martin line, sizeof(line)); 1322 1.7 martin msg_prompt_win( 1323 1.7 martin edit->pset->parts->pscheme->custom_attributes[attr_no]. 1324 1.7 martin label, -1, 18, 0, 0, line, line, sizeof(line)); 1325 1.7 martin edit->pset->parts->pscheme->custom_attribute_set_str( 1326 1.7 martin edit->pset->parts, edit->id, attr_no, line); 1327 1.1 dholland break; 1328 1.1 dholland } 1329 1.7 martin 1330 1.7 martin return 0; 1331 1.7 martin } 1332 1.7 martin 1333 1.7 martin 1334 1.7 martin /* 1335 1.7 martin * Some column width depend on translation, we will set these in 1336 1.7 martin * fmt_fspart_header and later use it when formatting single entries 1337 1.7 martin * in fmt_fspart_row. 1338 1.7 martin * The table consist of 3 "size like" columns, all fixed width, then 1339 1.7 martin * ptnheaders_fstype, part_header_col_flag, and finally the mount point 1340 1.7 martin * (which is variable width). 1341 1.7 martin */ 1342 1.7 martin static int fstype_width, flags_width; 1343 1.7 martin static char fspart_separator[MENUSTRSIZE]; 1344 1.7 martin static char fspart_title[2*MENUSTRSIZE]; 1345 1.7 martin 1346 1.7 martin /* 1347 1.7 martin * Format the header of the main partition editor menu. 1348 1.7 martin */ 1349 1.7 martin static void 1350 1.7 martin fmt_fspart_header(menudesc *menu, void *arg) 1351 1.7 martin { 1352 1.7 martin struct partition_usage_set *pset = arg; 1353 1.7 martin char total[6], free_space[6], scol[13], ecol[13], szcol[13], 1354 1.13 martin sepline[MENUSTRSIZE], *p, desc[MENUSTRSIZE]; 1355 1.7 martin const char *fstype, *flags; 1356 1.7 martin int i; 1357 1.13 martin size_t ptn; 1358 1.13 martin bool with_clone, with_inst_flag = pset->parts->parent == NULL; 1359 1.7 martin 1360 1.13 martin with_clone = false; 1361 1.13 martin for (ptn = 0; ptn < pset->num && !with_clone; ptn++) 1362 1.13 martin if (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) 1363 1.13 martin with_clone = true; 1364 1.7 martin humanize_number(total, sizeof total, 1365 1.20 martin pset->parts->disk_size * pset->parts->bytes_per_sector, 1366 1.7 martin "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 1367 1.7 martin humanize_number(free_space, sizeof free_space, 1368 1.20 martin pset->cur_free_space * pset->parts->bytes_per_sector, 1369 1.7 martin "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 1370 1.7 martin 1371 1.13 martin if (with_clone) 1372 1.13 martin strlcpy(desc, msg_string(MSG_clone_flag_desc), sizeof desc); 1373 1.13 martin else 1374 1.13 martin desc[0] = 0; 1375 1.13 martin if (pset->parts->pscheme->part_flag_desc) 1376 1.13 martin strlcat(desc, msg_string(pset->parts->pscheme->part_flag_desc), 1377 1.13 martin sizeof desc); 1378 1.13 martin 1379 1.7 martin msg_display_subst(MSG_fspart, 7, pset->parts->disk, 1380 1.7 martin msg_string(pset->parts->pscheme->name), 1381 1.7 martin msg_string(pset->parts->pscheme->short_name), 1382 1.7 martin with_inst_flag ? msg_string(MSG_ptn_instflag_desc) : "", 1383 1.13 martin desc, total, free_space); 1384 1.7 martin 1385 1.7 martin snprintf(scol, sizeof scol, "%s (%s)", 1386 1.7 martin msg_string(MSG_ptnheaders_start), multname); 1387 1.7 martin snprintf(ecol, sizeof ecol, "%s (%s)", 1388 1.7 martin msg_string(MSG_ptnheaders_end), multname); 1389 1.7 martin snprintf(szcol, sizeof szcol, "%s (%s)", 1390 1.7 martin msg_string(MSG_ptnheaders_size), multname); 1391 1.7 martin 1392 1.7 martin fstype = msg_string(MSG_ptnheaders_fstype); 1393 1.7 martin flags = msg_string(MSG_part_header_col_flag); 1394 1.7 martin fstype_width = max(strlen(fstype), 8); 1395 1.7 martin flags_width = strlen(flags); 1396 1.7 martin for (i = 0, p = sepline; i < fstype_width; i++) 1397 1.7 martin *p++ = '-'; 1398 1.7 martin for (i = 0, *p++ = ' '; i < flags_width; i++) 1399 1.7 martin *p++ = '-'; 1400 1.7 martin *p = 0; 1401 1.7 martin 1402 1.7 martin snprintf(fspart_separator, sizeof(fspart_separator), 1403 1.7 martin "------------ ------------ ------------ %s ----------------", 1404 1.7 martin sepline); 1405 1.7 martin 1406 1.7 martin snprintf(fspart_title, sizeof(fspart_title), 1407 1.7 martin " %12.12s %12.12s %12.12s %*s %*s %s\n" 1408 1.7 martin " %s", scol, ecol, szcol, fstype_width, fstype, 1409 1.7 martin flags_width, flags, msg_string(MSG_ptnheaders_filesystem), 1410 1.7 martin fspart_separator); 1411 1.7 martin 1412 1.7 martin msg_table_add("\n\n"); 1413 1.7 martin } 1414 1.7 martin 1415 1.7 martin /* 1416 1.7 martin * Format one partition entry in the main partition editor. 1417 1.7 martin */ 1418 1.7 martin static void 1419 1.7 martin fmt_fspart_row(menudesc *m, int ptn, void *arg) 1420 1.7 martin { 1421 1.7 martin struct partition_usage_set *pset = arg; 1422 1.7 martin struct disk_part_info info; 1423 1.7 martin daddr_t poffset, psize, pend; 1424 1.7 martin const char *desc; 1425 1.7 martin static const char *Yes; 1426 1.7 martin char flag_str[MENUSTRSIZE], *fp; 1427 1.7 martin unsigned inst_flags; 1428 1.14 martin #ifndef NO_CLONES 1429 1.13 martin size_t clone_cnt; 1430 1.14 martin #endif 1431 1.7 martin bool with_inst_flag = pset->parts->parent == NULL; 1432 1.7 martin 1433 1.7 martin if (Yes == NULL) 1434 1.7 martin Yes = msg_string(MSG_Yes); 1435 1.7 martin 1436 1.14 martin #ifndef NO_CLONES 1437 1.13 martin if ((pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) && 1438 1.13 martin pset->infos[ptn].cur_part_id == NO_PART) { 1439 1.13 martin psize = pset->infos[ptn].size / sizemult; 1440 1.13 martin if (pset->infos[ptn].clone_ndx < 1441 1.13 martin pset->infos[ptn].clone_src->num_sel) 1442 1.13 martin clone_cnt = 1; 1443 1.13 martin else 1444 1.13 martin clone_cnt = pset->infos[ptn].clone_src->num_sel; 1445 1.13 martin if (pset->infos[ptn].cur_part_id == NO_PART) 1446 1.13 martin wprintw(m->mw, " %12" PRIu64 1447 1.13 martin " [%zu %s]", psize, clone_cnt, 1448 1.13 martin msg_string(MSG_clone_target_disp)); 1449 1.13 martin else { 1450 1.13 martin poffset = pset->infos[ptn].cur_start / sizemult; 1451 1.13 martin pend = (pset->infos[ptn].cur_start + 1452 1.13 martin pset->infos[ptn].size) / sizemult - 1; 1453 1.13 martin wprintw(m->mw, "%12" PRIu64 " %12" PRIu64 " %12" PRIu64 1454 1.13 martin " [%zu %s]", 1455 1.13 martin poffset, pend, psize, clone_cnt, 1456 1.13 martin msg_string(MSG_clone_target_disp)); 1457 1.13 martin } 1458 1.13 martin if (m->title == fspart_title) 1459 1.13 martin m->opts[ptn].opt_flags |= OPT_IGNORE; 1460 1.13 martin else 1461 1.13 martin m->opts[ptn].opt_flags &= ~OPT_IGNORE; 1462 1.13 martin return; 1463 1.13 martin } 1464 1.14 martin #endif 1465 1.13 martin 1466 1.7 martin if (!real_partition(pset, ptn)) 1467 1.7 martin return; 1468 1.7 martin 1469 1.7 martin if (!pset->parts->pscheme->get_part_info(pset->parts, 1470 1.7 martin pset->infos[ptn].cur_part_id, &info)) 1471 1.7 martin return; 1472 1.7 martin 1473 1.13 martin /* 1474 1.13 martin * We use this function in multiple menus, but only want it 1475 1.13 martin * to play with enable/disable in a single one: 1476 1.13 martin */ 1477 1.13 martin if (m->title == fspart_title) { 1478 1.13 martin /* 1479 1.13 martin * Enable / disable this line if it is something 1480 1.13 martin * like RAW_PART 1481 1.13 martin */ 1482 1.13 martin if ((info.flags & 1483 1.13 martin (PTI_WHOLE_DISK|PTI_PSCHEME_INTERNAL|PTI_RAW_PART)) 1484 1.13 martin || (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS)) 1485 1.13 martin m->opts[ptn].opt_flags |= OPT_IGNORE; 1486 1.13 martin else 1487 1.13 martin m->opts[ptn].opt_flags &= ~OPT_IGNORE; 1488 1.13 martin } 1489 1.7 martin 1490 1.7 martin poffset = info.start / sizemult; 1491 1.7 martin psize = info.size / sizemult; 1492 1.7 martin if (psize == 0) 1493 1.7 martin pend = 0; 1494 1.7 martin else 1495 1.7 martin pend = (info.start + info.size) / sizemult - 1; 1496 1.7 martin 1497 1.7 martin if (info.flags & PTI_WHOLE_DISK) 1498 1.7 martin desc = msg_string(MSG_NetBSD_partition_cant_change); 1499 1.7 martin else if (info.flags & PTI_RAW_PART) 1500 1.7 martin desc = msg_string(MSG_Whole_disk_cant_change); 1501 1.7 martin else if (info.flags & PTI_BOOT) 1502 1.7 martin desc = msg_string(MSG_Boot_partition_cant_change); 1503 1.7 martin else 1504 1.7 martin desc = getfslabelname(info.fs_type, info.fs_sub_type); 1505 1.7 martin 1506 1.7 martin fp = flag_str; 1507 1.7 martin inst_flags = pset->infos[ptn].instflags; 1508 1.26 martin if (with_inst_flag && (info.flags & PTI_INSTALL_TARGET) && 1509 1.7 martin info.nat_type->generic_ptype == PT_root) { 1510 1.7 martin static char inst_flag; 1511 1.7 martin 1512 1.7 martin if (inst_flag == 0) 1513 1.7 martin inst_flag = msg_string(MSG_install_flag)[0]; 1514 1.7 martin *fp++ = inst_flag; 1515 1.7 martin } 1516 1.7 martin if (inst_flags & PUIINST_NEWFS) 1517 1.7 martin *fp++ = msg_string(MSG_newfs_flag)[0]; 1518 1.13 martin if (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) 1519 1.13 martin *fp++ = msg_string(MSG_clone_flag)[0]; 1520 1.7 martin *fp = 0; 1521 1.7 martin if (pset->parts->pscheme->get_part_attr_str != NULL) 1522 1.7 martin pset->parts->pscheme->get_part_attr_str(pset->parts, 1523 1.47 martin pset->infos[ptn].cur_part_id, fp, 1524 1.47 martin sizeof(flag_str)-1-(fp-flag_str)); 1525 1.7 martin 1526 1.7 martin /* if the fstype description does not fit, check if we can overrun */ 1527 1.7 martin if (strlen(desc) > (size_t)fstype_width && 1528 1.7 martin flag_str[0] == 0 && (info.last_mounted == NULL || 1529 1.7 martin info.last_mounted[0] == 0)) 1530 1.7 martin wprintw(m->mw, "%12" PRIu64 " %12" PRIu64 " %12" PRIu64 1531 1.7 martin " %s", 1532 1.7 martin poffset, pend, psize, desc); 1533 1.7 martin else 1534 1.7 martin wprintw(m->mw, "%12" PRIu64 " %12" PRIu64 " %12" PRIu64 1535 1.7 martin " %*.*s %*s %s", 1536 1.7 martin poffset, pend, psize, fstype_width, fstype_width, desc, 1537 1.7 martin -flags_width, flag_str, 1538 1.7 martin (inst_flags & PUIINST_MOUNT) && info.last_mounted && 1539 1.7 martin info.last_mounted[0] ? info.last_mounted : ""); 1540 1.1 dholland } 1541 1.1 dholland 1542 1.14 martin #ifndef NO_CLONES 1543 1.1 dholland static int 1544 1.13 martin part_ext_clone(menudesc *m, void *arg) 1545 1.13 martin { 1546 1.13 martin struct selected_partitions selected, *clone_src; 1547 1.13 martin struct clone_target_menu_data data; 1548 1.13 martin struct partition_usage_set *pset = arg; 1549 1.13 martin struct part_usage_info *p; 1550 1.13 martin struct disk_part_info sinfo, cinfo; 1551 1.13 martin struct disk_partitions *csrc; 1552 1.13 martin struct disk_part_free_space space; 1553 1.13 martin menu_ent *men; 1554 1.13 martin daddr_t clone_size, free_size, offset, align; 1555 1.13 martin int num_men, i; 1556 1.13 martin size_t s, clone_cnt; 1557 1.13 martin part_id cid; 1558 1.13 martin struct clone_data { 1559 1.13 martin struct disk_part_info info; 1560 1.13 martin part_id new_id; 1561 1.13 martin size_t ndx; 1562 1.13 martin }; 1563 1.13 martin struct clone_data *clones = NULL; 1564 1.13 martin 1565 1.13 martin if (!select_partitions(&selected, pm->parts)) 1566 1.13 martin return 0; 1567 1.13 martin 1568 1.13 martin clone_size = selected_parts_size(&selected); 1569 1.13 martin num_men = pset->num+1; 1570 1.13 martin men = calloc(num_men, sizeof *men); 1571 1.13 martin if (men == NULL) 1572 1.13 martin return 0; 1573 1.13 martin for (i = 0; i < num_men; i++) { 1574 1.13 martin men[i].opt_action = clone_target_select; 1575 1.13 martin if (i == 0) 1576 1.13 martin free_size = pset->infos[i].cur_start; 1577 1.13 martin else if (i > 0 && (size_t)i < pset->num) 1578 1.13 martin free_size = pset->infos[i].cur_start - 1579 1.13 martin pset->infos[i-1].cur_start - pset->infos[i-1].size; 1580 1.13 martin else 1581 1.13 martin free_size = pset->parts->free_space; 1582 1.13 martin if (free_size < clone_size) 1583 1.13 martin men[i].opt_flags = OPT_IGNORE; 1584 1.13 martin } 1585 1.13 martin men[num_men-1].opt_name = MSG_clone_target_end; 1586 1.13 martin 1587 1.13 martin memset(&data, 0, sizeof data); 1588 1.13 martin data.usage = *pset; 1589 1.13 martin data.res = -1; 1590 1.13 martin 1591 1.13 martin data.usage.menu = new_menu(MSG_clone_target_hdr, 1592 1.13 martin men, num_men, 3, 2, 0, 65, MC_SCROLL, 1593 1.13 martin NULL, fmt_fspart_row, NULL, NULL, MSG_cancel); 1594 1.13 martin process_menu(data.usage.menu, &data); 1595 1.13 martin free_menu(data.usage.menu); 1596 1.13 martin free(men); 1597 1.13 martin 1598 1.13 martin if (data.res < 0) 1599 1.13 martin goto err; 1600 1.13 martin 1601 1.13 martin /* create temporary infos for all clones that work out */ 1602 1.13 martin clone_cnt = 0; 1603 1.13 martin clones = calloc(selected.num_sel, sizeof(*clones)); 1604 1.13 martin if (clones == NULL) 1605 1.13 martin goto err; 1606 1.13 martin 1607 1.13 martin clone_src = malloc(sizeof(selected)); 1608 1.13 martin if (clone_src == NULL) 1609 1.13 martin goto err; 1610 1.32 rillig *clone_src = selected; 1611 1.13 martin 1612 1.13 martin /* find selected offset from data.res and insert clones there */ 1613 1.13 martin align = pset->parts->pscheme->get_part_alignment(pset->parts); 1614 1.13 martin offset = -1; 1615 1.13 martin if (data.res > 0) 1616 1.13 martin offset = pset->infos[data.res-1].cur_start 1617 1.13 martin + pset->infos[data.res-1].size; 1618 1.13 martin else 1619 1.13 martin offset = 0; 1620 1.13 martin for (s = 0; s < selected.num_sel; s++) { 1621 1.13 martin csrc = selected.selection[s].parts; 1622 1.13 martin cid = selected.selection[s].id; 1623 1.13 martin csrc->pscheme->get_part_info(csrc, cid, &sinfo); 1624 1.13 martin if (!pset->parts->pscheme->adapt_foreign_part_info( 1625 1.13 martin pset->parts, &cinfo, csrc->pscheme, &sinfo)) 1626 1.13 martin continue; 1627 1.13 martin size_t cnt = pset->parts->pscheme->get_free_spaces( 1628 1.13 martin pset->parts, &space, 1, cinfo.size-align, align, 1629 1.13 martin offset, -1); 1630 1.13 martin if (cnt == 0) 1631 1.13 martin continue; 1632 1.13 martin cinfo.start = space.start; 1633 1.13 martin cid = pset->parts->pscheme->add_partition( 1634 1.13 martin pset->parts, &cinfo, NULL); 1635 1.13 martin if (cid == NO_PART) 1636 1.13 martin continue; 1637 1.13 martin pset->parts->pscheme->get_part_info(pset->parts, cid, &cinfo); 1638 1.13 martin clones[clone_cnt].info = cinfo; 1639 1.13 martin clones[clone_cnt].new_id = cid; 1640 1.13 martin clones[clone_cnt].ndx = s; 1641 1.13 martin clone_cnt++; 1642 1.27 martin offset = roundup(cinfo.start+cinfo.size, align); 1643 1.13 martin } 1644 1.13 martin 1645 1.13 martin /* insert new clone records at offset data.res */ 1646 1.13 martin men = realloc(m->opts, (m->numopts+clone_cnt)*sizeof(*m->opts)); 1647 1.13 martin if (men == NULL) 1648 1.13 martin goto err; 1649 1.13 martin pset->menu_opts = men; 1650 1.13 martin m->opts = men; 1651 1.13 martin m->numopts += clone_cnt; 1652 1.13 martin 1653 1.13 martin p = realloc(pset->infos, (pset->num+clone_cnt)*sizeof(*pset->infos)); 1654 1.13 martin if (p == NULL) 1655 1.13 martin goto err; 1656 1.13 martin pset->infos = p; 1657 1.13 martin 1658 1.13 martin men += data.res; 1659 1.13 martin p += data.res; 1660 1.13 martin memmove(men+clone_cnt, men, 1661 1.13 martin sizeof(*men)*(m->numopts-data.res-clone_cnt)); 1662 1.13 martin if (pset->num > (size_t)data.res) 1663 1.13 martin memmove(p+clone_cnt, p, sizeof(*p)*(pset->num-data.res)); 1664 1.13 martin memset(men, 0, sizeof(*men)*clone_cnt); 1665 1.13 martin memset(p, 0, sizeof(*p)*clone_cnt); 1666 1.13 martin for (s = 0; s < clone_cnt; s++) { 1667 1.13 martin p[s].cur_part_id = clones[s].new_id; 1668 1.13 martin p[s].cur_start = clones[s].info.start; 1669 1.13 martin p[s].size = clones[s].info.size; 1670 1.13 martin p[s].cur_flags = clones[s].info.flags; 1671 1.13 martin p[s].flags = PUIFLG_CLONE_PARTS; 1672 1.13 martin p[s].parts = pset->parts; 1673 1.13 martin p[s].clone_src = clone_src; 1674 1.13 martin p[s].clone_ndx = s; 1675 1.13 martin } 1676 1.13 martin free(clones); 1677 1.13 martin m->cursel = ((size_t)data.res >= pset->num) ? 0 : data.res+clone_cnt; 1678 1.13 martin pset->num += clone_cnt; 1679 1.13 martin m->h = 0; 1680 1.13 martin resize_menu_height(m); 1681 1.13 martin 1682 1.13 martin return -1; 1683 1.13 martin 1684 1.13 martin err: 1685 1.13 martin free(clones); 1686 1.13 martin free_selected_partitions(&selected); 1687 1.13 martin return 0; 1688 1.13 martin } 1689 1.14 martin #endif 1690 1.13 martin 1691 1.13 martin static int 1692 1.7 martin edit_fspart_pack(menudesc *m, void *arg) 1693 1.1 dholland { 1694 1.7 martin struct partition_usage_set *pset = arg; 1695 1.7 martin char buf[STRSIZE]; 1696 1.1 dholland 1697 1.7 martin if (!pset->parts->pscheme->get_disk_pack_name(pset->parts, 1698 1.7 martin buf, sizeof buf)) 1699 1.7 martin return 0; 1700 1.7 martin 1701 1.7 martin msg_prompt_win(MSG_edit_disk_pack_hdr, 1702 1.7 martin -1, 18, 0, -1, buf, buf, sizeof(buf)); 1703 1.7 martin 1704 1.7 martin pset->parts->pscheme->set_disk_pack_name(pset->parts, buf); 1705 1.1 dholland return 0; 1706 1.1 dholland } 1707 1.1 dholland 1708 1.7 martin static int 1709 1.7 martin edit_fspart_add(menudesc *m, void *arg) 1710 1.7 martin { 1711 1.7 martin struct partition_usage_set *pset = arg; 1712 1.7 martin struct part_usage_info *ninfo; 1713 1.7 martin menu_ent *nmenopts; 1714 1.7 martin size_t cnt, off; 1715 1.7 martin 1716 1.7 martin ninfo = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos)); 1717 1.7 martin if (ninfo == NULL) 1718 1.7 martin return 0; 1719 1.7 martin pset->infos = ninfo; 1720 1.7 martin off = pset->parts->num_part; 1721 1.7 martin cnt = pset->num-pset->parts->num_part; 1722 1.7 martin if (cnt > 0) 1723 1.7 martin memmove(pset->infos+off+1,pset->infos+off, 1724 1.7 martin cnt*sizeof(*pset->infos)); 1725 1.7 martin memset(pset->infos+off, 0, sizeof(*pset->infos)); 1726 1.7 martin 1727 1.7 martin nmenopts = realloc(m->opts, (m->numopts+1)*sizeof(*m->opts)); 1728 1.7 martin if (nmenopts == NULL) 1729 1.7 martin return 0; 1730 1.7 martin memmove(nmenopts+off+1, nmenopts+off, 1731 1.7 martin (m->numopts-off)*sizeof(*nmenopts)); 1732 1.7 martin memset(&nmenopts[off], 0, sizeof(nmenopts[off])); 1733 1.7 martin nmenopts[off].opt_action = edit_ptn; 1734 1.7 martin pset->menu_opts = m->opts = nmenopts; 1735 1.7 martin m->numopts++; 1736 1.7 martin m->cursel = off; 1737 1.7 martin pset->num++; 1738 1.7 martin 1739 1.7 martin /* now update edit menu to fit */ 1740 1.7 martin m->h = 0; 1741 1.7 martin resize_menu_height(m); 1742 1.7 martin 1743 1.7 martin /* and directly invoke the partition editor for the new part */ 1744 1.7 martin edit_ptn(m, arg); 1745 1.7 martin 1746 1.7 martin show_partition_adder(m, pset); 1747 1.7 martin 1748 1.7 martin return -1; 1749 1.7 martin } 1750 1.7 martin 1751 1.1 dholland static void 1752 1.7 martin add_partition_adder(menudesc *m, struct partition_usage_set *pset) 1753 1.1 dholland { 1754 1.7 martin struct part_usage_info *ninfo; 1755 1.7 martin menu_ent *nmenopts; 1756 1.7 martin size_t off; 1757 1.7 martin 1758 1.7 martin ninfo = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos)); 1759 1.7 martin if (ninfo == NULL) 1760 1.7 martin return; 1761 1.7 martin pset->infos = ninfo; 1762 1.7 martin off = pset->parts->num_part+1; 1763 1.1 dholland 1764 1.7 martin nmenopts = realloc(m->opts, (m->numopts+1)*sizeof(*m->opts)); 1765 1.7 martin if (nmenopts == NULL) 1766 1.7 martin return; 1767 1.7 martin memmove(nmenopts+off+1, nmenopts+off, 1768 1.7 martin (m->numopts-off)*sizeof(*nmenopts)); 1769 1.7 martin memset(&nmenopts[off], 0, sizeof(nmenopts[off])); 1770 1.7 martin 1771 1.7 martin nmenopts[off].opt_name = MSG_addpart; 1772 1.7 martin nmenopts[off].opt_flags = OPT_SUB; 1773 1.7 martin nmenopts[off].opt_action = edit_fspart_add; 1774 1.7 martin 1775 1.7 martin m->opts = nmenopts; 1776 1.7 martin m->numopts++; 1777 1.7 martin } 1778 1.1 dholland 1779 1.7 martin static void 1780 1.7 martin remove_partition_adder(menudesc *m, struct partition_usage_set *pset) 1781 1.7 martin { 1782 1.7 martin size_t off; 1783 1.1 dholland 1784 1.7 martin off = pset->parts->num_part+1; 1785 1.7 martin memmove(m->opts+off, m->opts+off+1, 1786 1.7 martin (m->numopts-off-1)*sizeof(*m->opts)); 1787 1.7 martin m->numopts--; 1788 1.1 dholland } 1789 1.1 dholland 1790 1.1 dholland /* 1791 1.7 martin * Called whenever the "add a partition" option may need to be removed 1792 1.7 martin * or added 1793 1.1 dholland */ 1794 1.7 martin static void 1795 1.7 martin show_partition_adder(menudesc *m, struct partition_usage_set *pset) 1796 1.1 dholland { 1797 1.18 martin if (m->opts == NULL) 1798 1.18 martin return; 1799 1.18 martin 1800 1.7 martin bool can_add_partition = pset->parts->pscheme->can_add_partition( 1801 1.7 martin pset->parts); 1802 1.7 martin bool part_adder_present = 1803 1.7 martin (m->opts[pset->parts->num_part].opt_flags & OPT_IGNORE) && 1804 1.7 martin (m->opts[pset->parts->num_part+1].opt_action == edit_fspart_add); 1805 1.1 dholland 1806 1.7 martin if (can_add_partition == part_adder_present) 1807 1.7 martin return; 1808 1.1 dholland 1809 1.7 martin if (can_add_partition) 1810 1.7 martin add_partition_adder(m, pset); 1811 1.7 martin else 1812 1.7 martin remove_partition_adder(m, pset); 1813 1.1 dholland 1814 1.7 martin /* now update edit menu to fit */ 1815 1.7 martin m->h = 0; 1816 1.7 martin resize_menu_height(m); 1817 1.7 martin } 1818 1.1 dholland 1819 1.7 martin static int 1820 1.7 martin edit_fspart_abort(menudesc *m, void *arg) 1821 1.7 martin { 1822 1.7 martin struct partition_usage_set *pset = arg; 1823 1.1 dholland 1824 1.7 martin pset->ok = false; 1825 1.7 martin return 1; 1826 1.1 dholland } 1827 1.1 dholland 1828 1.1 dholland /* 1829 1.7 martin * Check a disklabel. 1830 1.7 martin * If there are overlapping active partitions, 1831 1.7 martin * Ask the user if they want to edit the partition or give up. 1832 1.1 dholland */ 1833 1.1 dholland int 1834 1.18 martin edit_and_check_label(struct pm_devs *p, struct partition_usage_set *pset, 1835 1.18 martin bool install) 1836 1.1 dholland { 1837 1.7 martin menu_ent *op; 1838 1.7 martin size_t cnt, i; 1839 1.7 martin bool may_add = pset->parts->pscheme->can_add_partition(pset->parts); 1840 1.7 martin bool may_edit_pack = 1841 1.7 martin pset->parts->pscheme->get_disk_pack_name != NULL && 1842 1.7 martin pset->parts->pscheme->set_disk_pack_name != NULL; 1843 1.7 martin 1844 1.14 martin #ifdef NO_CLONES 1845 1.14 martin #define C_M_ITEMS 0 1846 1.14 martin #else 1847 1.14 martin #define C_M_ITEMS 1 1848 1.14 martin #endif 1849 1.7 martin pset->menu_opts = calloc(pset->parts->num_part 1850 1.14 martin +3+C_M_ITEMS+may_add+may_edit_pack, 1851 1.7 martin sizeof *pset->menu_opts); 1852 1.7 martin if (pset->menu_opts == NULL) 1853 1.7 martin return 0; 1854 1.1 dholland 1855 1.7 martin op = pset->menu_opts; 1856 1.7 martin for (i = 0; i < pset->parts->num_part; i++) { 1857 1.7 martin op->opt_action = edit_ptn; 1858 1.7 martin op++; 1859 1.7 martin } 1860 1.7 martin /* separator line between partitions and actions */ 1861 1.7 martin op->opt_name = fspart_separator; 1862 1.7 martin op->opt_flags = OPT_IGNORE|OPT_NOSHORT; 1863 1.7 martin op++; 1864 1.7 martin 1865 1.7 martin /* followed by new partition adder */ 1866 1.7 martin if (may_add) { 1867 1.7 martin op->opt_name = MSG_addpart; 1868 1.7 martin op->opt_flags = OPT_SUB; 1869 1.7 martin op->opt_action = edit_fspart_add; 1870 1.7 martin op++; 1871 1.7 martin } 1872 1.32 rillig 1873 1.7 martin /* and unit changer */ 1874 1.7 martin op->opt_name = MSG_askunits; 1875 1.7 martin op->opt_menu = MENU_sizechoice; 1876 1.7 martin op->opt_flags = OPT_SUB; 1877 1.7 martin op->opt_action = NULL; 1878 1.7 martin op++; 1879 1.7 martin 1880 1.7 martin if (may_edit_pack) { 1881 1.7 martin op->opt_name = MSG_editpack; 1882 1.7 martin op->opt_flags = OPT_SUB; 1883 1.7 martin op->opt_action = edit_fspart_pack; 1884 1.7 martin op++; 1885 1.7 martin } 1886 1.13 martin 1887 1.14 martin #ifndef NO_CLONES 1888 1.13 martin /* add a clone-from-elsewhere option */ 1889 1.13 martin op->opt_name = MSG_clone_from_elsewhere; 1890 1.13 martin op->opt_action = part_ext_clone; 1891 1.13 martin op++; 1892 1.14 martin #endif 1893 1.32 rillig 1894 1.7 martin /* and abort option */ 1895 1.7 martin op->opt_name = MSG_cancel; 1896 1.7 martin op->opt_flags = OPT_EXIT; 1897 1.7 martin op->opt_action = edit_fspart_abort; 1898 1.7 martin op++; 1899 1.7 martin cnt = op - pset->menu_opts; 1900 1.14 martin assert(cnt == pset->parts->num_part+3+C_M_ITEMS+may_add+may_edit_pack); 1901 1.7 martin 1902 1.7 martin pset->menu = new_menu(fspart_title, pset->menu_opts, cnt, 1903 1.7 martin 0, -1, 0, 74, 1904 1.7 martin MC_ALWAYS_SCROLL|MC_NOBOX|MC_DFLTEXIT| 1905 1.7 martin MC_NOCLEAR|MC_CONTINUOUS, 1906 1.7 martin fmt_fspart_header, fmt_fspart_row, NULL, NULL, 1907 1.7 martin MSG_partition_sizes_ok); 1908 1.7 martin 1909 1.7 martin if (pset->menu < 0) { 1910 1.7 martin free(pset->menu_opts); 1911 1.7 martin pset->menu_opts = NULL; 1912 1.7 martin return 0; 1913 1.7 martin } 1914 1.1 dholland 1915 1.7 martin p->current_cylsize = p->dlcylsize; 1916 1.1 dholland 1917 1.7 martin for (;;) { 1918 1.7 martin /* first give the user the option to edit the label... */ 1919 1.7 martin pset->ok = true; 1920 1.7 martin process_menu(pset->menu, pset); 1921 1.7 martin if (!pset->ok) { 1922 1.7 martin i = 0; 1923 1.7 martin break; 1924 1.7 martin } 1925 1.1 dholland 1926 1.7 martin /* User thinks the label is OK. */ 1927 1.18 martin i = verify_parts(pset, install); 1928 1.7 martin if (i == 1) 1929 1.7 martin continue; 1930 1.7 martin break; 1931 1.1 dholland } 1932 1.7 martin free(pset->menu_opts); 1933 1.7 martin pset->menu_opts = NULL; 1934 1.7 martin free_menu(pset->menu); 1935 1.7 martin pset->menu = -1; 1936 1.1 dholland 1937 1.7 martin return i != 0; 1938 1.1 dholland } 1939 1.1 dholland 1940 1.1 dholland /* 1941 1.31 wiz * strip trailing / to avoid confusion in path comparisons later 1942 1.10 martin */ 1943 1.10 martin void 1944 1.10 martin canonicalize_last_mounted(char *path) 1945 1.10 martin { 1946 1.10 martin char *p; 1947 1.10 martin 1948 1.11 martin if (path == NULL) 1949 1.11 martin return; 1950 1.11 martin 1951 1.11 martin if (strcmp(path, "/") == 0) 1952 1.11 martin return; /* in this case a "trailing" slash is allowed */ 1953 1.11 martin 1954 1.10 martin for (;;) { 1955 1.10 martin p = strrchr(path, '/'); 1956 1.10 martin if (p == NULL) 1957 1.10 martin return; 1958 1.10 martin if (p[1] != 0) 1959 1.10 martin return; 1960 1.10 martin p[0] = 0; 1961 1.10 martin } 1962 1.10 martin } 1963 1.10 martin 1964 1.10 martin /* 1965 1.1 dholland * Try to get 'last mounted on' (or equiv) from fs superblock. 1966 1.1 dholland */ 1967 1.1 dholland const char * 1968 1.7 martin get_last_mounted(int fd, daddr_t partstart, uint *fs_type, uint *fs_sub_type, 1969 1.7 martin uint flags) 1970 1.1 dholland { 1971 1.50 martin static char sblk[SBLOCKSIZE] __aligned(8); /* is this enough? */ 1972 1.1 dholland struct fs *SB = (struct fs *)sblk; 1973 1.7 martin static const off_t sblocks[] = SBLOCKSEARCH; 1974 1.7 martin const off_t *sbp; 1975 1.1 dholland const char *mnt = NULL; 1976 1.1 dholland int len; 1977 1.1 dholland 1978 1.1 dholland if (fd == -1) 1979 1.1 dholland return ""; 1980 1.1 dholland 1981 1.7 martin if (fs_type) 1982 1.7 martin *fs_type = 0; 1983 1.7 martin if (fs_sub_type) 1984 1.7 martin *fs_sub_type = 0; 1985 1.7 martin 1986 1.1 dholland /* Check UFS1/2 (and hence LFS) superblock */ 1987 1.1 dholland for (sbp = sblocks; mnt == NULL && *sbp != -1; sbp++) { 1988 1.1 dholland if (pread(fd, sblk, sizeof sblk, 1989 1.7 martin (off_t)partstart * (off_t)512 + *sbp) != sizeof sblk) 1990 1.7 martin continue; 1991 1.7 martin 1992 1.7 martin /* 1993 1.7 martin * If start of partition and allowed by flags check 1994 1.7 martin * for other fs types 1995 1.7 martin */ 1996 1.7 martin if (*sbp == 0 && (flags & GLM_MAYBE_FAT32) && 1997 1.7 martin sblk[0x42] == 0x29 && memcmp(sblk + 0x52, "FAT", 3) == 0) { 1998 1.7 martin /* Probably a FAT filesystem, report volume name */ 1999 1.7 martin size_t i; 2000 1.7 martin for (i = 0x51; i >= 0x47; i--) { 2001 1.7 martin if (sblk[i] != ' ') 2002 1.7 martin break; 2003 1.7 martin sblk[i] = 0; 2004 1.7 martin } 2005 1.7 martin sblk[0x52] = 0; 2006 1.7 martin if (fs_type) 2007 1.7 martin *fs_type = FS_MSDOS; 2008 1.7 martin if (fs_sub_type) 2009 1.7 martin *fs_sub_type = sblk[0x53]; 2010 1.7 martin return sblk + 0x47; 2011 1.7 martin } else if (*sbp == 0 && (flags & GLM_MAYBE_NTFS) && 2012 1.7 martin memcmp(sblk+3, "NTFS ", 8) == 0) { 2013 1.7 martin if (fs_type) 2014 1.7 martin *fs_type = FS_NTFS; 2015 1.7 martin if (fs_sub_type) 2016 1.7 martin *fs_sub_type = MBR_PTYPE_NTFS; 2017 1.7 martin /* XXX dig for volume name attribute ? */ 2018 1.7 martin return ""; 2019 1.7 martin } 2020 1.7 martin 2021 1.7 martin if (!(flags & GLM_LIKELY_FFS)) 2022 1.1 dholland continue; 2023 1.7 martin 2024 1.1 dholland /* Maybe we should validate the checksum??? */ 2025 1.1 dholland switch (SB->fs_magic) { 2026 1.1 dholland case FS_UFS1_MAGIC: 2027 1.1 dholland case FS_UFS1_MAGIC_SWAPPED: 2028 1.1 dholland if (!(SB->fs_old_flags & FS_FLAGS_UPDATED)) { 2029 1.1 dholland if (*sbp == SBLOCK_UFS1) 2030 1.1 dholland mnt = (const char *)SB->fs_fsmnt; 2031 1.1 dholland } else { 2032 1.1 dholland /* Check we have the main superblock */ 2033 1.1 dholland if (SB->fs_sblockloc == *sbp) 2034 1.1 dholland mnt = (const char *)SB->fs_fsmnt; 2035 1.1 dholland } 2036 1.7 martin if (fs_type) 2037 1.7 martin *fs_type = FS_BSDFFS; 2038 1.7 martin if (fs_sub_type) 2039 1.12 martin *fs_sub_type = 1; 2040 1.1 dholland continue; 2041 1.1 dholland case FS_UFS2_MAGIC: 2042 1.42 chs case FS_UFS2EA_MAGIC: 2043 1.1 dholland case FS_UFS2_MAGIC_SWAPPED: 2044 1.42 chs case FS_UFS2EA_MAGIC_SWAPPED: 2045 1.1 dholland /* Check we have the main superblock */ 2046 1.1 dholland if (SB->fs_sblockloc == *sbp) { 2047 1.1 dholland mnt = (const char *)SB->fs_fsmnt; 2048 1.7 martin if (fs_type) 2049 1.7 martin *fs_type = FS_BSDFFS; 2050 1.7 martin if (fs_sub_type) 2051 1.7 martin *fs_sub_type = 2; 2052 1.1 dholland } 2053 1.1 dholland continue; 2054 1.1 dholland } 2055 1.1 dholland } 2056 1.1 dholland 2057 1.1 dholland if (mnt == NULL) 2058 1.1 dholland return ""; 2059 1.1 dholland 2060 1.1 dholland /* If sysinst mounted this last then strip prefix */ 2061 1.1 dholland len = strlen(targetroot_mnt); 2062 1.1 dholland if (memcmp(mnt, targetroot_mnt, len) == 0) { 2063 1.1 dholland if (mnt[len] == 0) 2064 1.1 dholland return "/"; 2065 1.1 dholland if (mnt[len] == '/') 2066 1.1 dholland return mnt + len; 2067 1.1 dholland } 2068 1.1 dholland return mnt; 2069 1.1 dholland #undef SB 2070 1.1 dholland } 2071 1.1 dholland 2072 1.1 dholland /* Ask for a partition offset, check bounds and do the needed roundups */ 2073 1.7 martin daddr_t 2074 1.7 martin getpartoff(struct disk_partitions *parts, daddr_t defpartstart) 2075 1.1 dholland { 2076 1.7 martin char defstart[24], isize[24], maxpart, minspace, maxspace, 2077 1.7 martin *prompt, *label_msg, valid_parts[4], valid_spaces[4], 2078 1.7 martin space_prompt[1024], *head, *hint_part, *hint_space, *tail; 2079 1.7 martin size_t num_freespace, spaces, ndx; 2080 1.7 martin struct disk_part_free_space *freespace; 2081 1.7 martin daddr_t i, localsizemult, ptn_alignment, min, max; 2082 1.7 martin part_id partn; 2083 1.7 martin struct disk_part_info info; 2084 1.7 martin const char *errmsg = NULL; 2085 1.7 martin 2086 1.7 martin min = parts->disk_start; 2087 1.7 martin max = min + parts->disk_size; 2088 1.7 martin 2089 1.7 martin /* upper bound on the number of free spaces, plus some slope */ 2090 1.7 martin num_freespace = parts->num_part * 2 + 5; 2091 1.7 martin freespace = calloc(num_freespace, sizeof(*freespace)); 2092 1.7 martin if (freespace == NULL) 2093 1.7 martin return -1; 2094 1.32 rillig 2095 1.7 martin ptn_alignment = parts->pscheme->get_part_alignment(parts); 2096 1.7 martin spaces = parts->pscheme->get_free_spaces(parts, freespace, 2097 1.7 martin num_freespace, max(sizemult, ptn_alignment), ptn_alignment, -1, 2098 1.7 martin defpartstart); 2099 1.7 martin 2100 1.7 martin maxpart = 'a' + parts->num_part -1; 2101 1.7 martin if (parts->num_part > 1) { 2102 1.7 martin snprintf(valid_parts, sizeof valid_parts, "a-%c", maxpart); 2103 1.7 martin } else if (parts->num_part == 1) { 2104 1.7 martin snprintf(valid_parts, sizeof valid_parts, " %c", maxpart); 2105 1.7 martin } else { 2106 1.7 martin strcpy(valid_parts, "---"); 2107 1.7 martin } 2108 1.7 martin if (spaces > 1) { 2109 1.7 martin minspace = maxpart + 1; 2110 1.7 martin maxspace = minspace + spaces -1; 2111 1.7 martin snprintf(valid_spaces, sizeof valid_spaces, "%c-%c", minspace, 2112 1.7 martin maxspace); 2113 1.7 martin } else if (spaces == 1) { 2114 1.7 martin maxspace = minspace = maxpart + 1; 2115 1.7 martin snprintf(valid_spaces, sizeof valid_spaces, " %c", minspace); 2116 1.7 martin } else { 2117 1.7 martin minspace = 0; 2118 1.7 martin maxspace = 0; 2119 1.7 martin strcpy(valid_spaces, "---"); 2120 1.7 martin } 2121 1.7 martin 2122 1.7 martin /* Add description of start/size to user prompt */ 2123 1.7 martin const char *mstr = msg_string(MSG_free_space_line); 2124 1.7 martin space_prompt[0] = 0; 2125 1.7 martin for (ndx = 0; ndx < spaces; ndx++) { 2126 1.7 martin char str_start[40], str_end[40], str_size[40], str_tag[4]; 2127 1.7 martin 2128 1.7 martin sprintf(str_tag, "%c: ", minspace+(int)ndx); 2129 1.7 martin sprintf(str_start, "%" PRIu64, freespace[ndx].start / sizemult); 2130 1.7 martin sprintf(str_end, "%" PRIu64, 2131 1.7 martin (freespace[ndx].start + freespace[ndx].size) / sizemult); 2132 1.7 martin sprintf(str_size, "%" PRIu64, freespace[ndx].size / sizemult); 2133 1.7 martin const char *args[4] = { str_start, str_end, str_size, 2134 1.7 martin multname }; 2135 1.7 martin char *line = str_arg_subst(mstr, 4, args); 2136 1.7 martin strlcat(space_prompt, str_tag, sizeof(space_prompt)); 2137 1.7 martin size_t len = strlcat(space_prompt, line, sizeof(space_prompt)); 2138 1.7 martin free (line); 2139 1.7 martin if (len >= sizeof space_prompt) 2140 1.7 martin break; 2141 1.7 martin } 2142 1.7 martin 2143 1.7 martin const char *args[] = { valid_parts, valid_spaces, multname }; 2144 1.7 martin hint_part = NULL; 2145 1.7 martin hint_space = NULL; 2146 1.7 martin head = str_arg_subst(msg_string(MSG_label_offset_head), 2147 1.7 martin __arraycount(args), args); 2148 1.7 martin if (parts->num_part) 2149 1.7 martin hint_part = str_arg_subst(msg_string( 2150 1.7 martin MSG_label_offset_part_hint), __arraycount(args), args); 2151 1.7 martin if (spaces) 2152 1.7 martin hint_space = str_arg_subst(msg_string( 2153 1.7 martin MSG_label_offset_space_hint), __arraycount(args), args); 2154 1.7 martin tail = str_arg_subst(msg_string(MSG_label_offset_tail), 2155 1.7 martin __arraycount(args), args); 2156 1.7 martin 2157 1.7 martin if (hint_part && hint_space) 2158 1.7 martin asprintf(&label_msg, "%s\n%s\n%s\n\n%s\n%s", 2159 1.7 martin head, hint_part, hint_space, space_prompt, tail); 2160 1.7 martin else if (hint_part) 2161 1.7 martin asprintf(&label_msg, "%s\n%s\n\n%s", 2162 1.7 martin head, hint_part, tail); 2163 1.7 martin else if (hint_space) 2164 1.7 martin asprintf(&label_msg, "%s\n%s\n\n%s\n%s", 2165 1.7 martin head, hint_space, space_prompt, tail); 2166 1.7 martin else 2167 1.7 martin asprintf(&label_msg, "%s\n\n%s", 2168 1.7 martin head, tail); 2169 1.7 martin free(head); free(hint_part); free(hint_space); free(tail); 2170 1.1 dholland 2171 1.7 martin localsizemult = sizemult; 2172 1.7 martin errmsg = NULL; 2173 1.1 dholland for (;;) { 2174 1.7 martin snprintf(defstart, sizeof defstart, "%" PRIu64, 2175 1.7 martin defpartstart/sizemult); 2176 1.7 martin if (errmsg != NULL && errmsg[0] != 0) 2177 1.7 martin asprintf(&prompt, "%s\n\n%s", errmsg, label_msg); 2178 1.7 martin else 2179 1.7 martin prompt = label_msg; 2180 1.7 martin msg_prompt_win(prompt, -1, 13, 70, -1, 2181 1.7 martin (defpartstart > 0) ? defstart : NULL, isize, sizeof isize); 2182 1.7 martin if (label_msg != prompt) 2183 1.7 martin free(prompt); 2184 1.7 martin if (strcmp(defstart, isize) == 0) { 2185 1.1 dholland /* Don't do rounding if default accepted */ 2186 1.7 martin i = defpartstart; 2187 1.7 martin break; 2188 1.7 martin } 2189 1.1 dholland if (isize[1] == '\0' && isize[0] >= 'a' && 2190 1.7 martin isize[0] <= maxpart) { 2191 1.1 dholland partn = isize[0] - 'a'; 2192 1.7 martin if (parts->pscheme->get_part_info(parts, partn, 2193 1.7 martin &info)) { 2194 1.7 martin i = info.start + info.size; 2195 1.7 martin localsizemult = 1; 2196 1.7 martin } else { 2197 1.7 martin errmsg = msg_string(MSG_invalid_sector_number); 2198 1.7 martin continue; 2199 1.7 martin } 2200 1.7 martin } else if (isize[1] == '\0' && isize[0] >= minspace && 2201 1.7 martin isize[0] <= maxspace) { 2202 1.7 martin ndx = isize[0] - minspace; 2203 1.7 martin i = freespace[ndx].start; 2204 1.1 dholland localsizemult = 1; 2205 1.1 dholland } else if (atoi(isize) == -1) { 2206 1.7 martin i = min; 2207 1.1 dholland localsizemult = 1; 2208 1.1 dholland } else { 2209 1.20 martin i = parse_disk_pos(isize, &localsizemult, 2210 1.20 martin parts->bytes_per_sector, 2211 1.19 martin parts->pscheme->get_cylinder_size(parts), NULL); 2212 1.7 martin if (i < 0) { 2213 1.1 dholland errmsg = msg_string(MSG_invalid_sector_number); 2214 1.1 dholland continue; 2215 1.1 dholland } 2216 1.1 dholland } 2217 1.1 dholland /* round to cylinder size if localsizemult != 1 */ 2218 1.19 martin int cylsize = parts->pscheme->get_cylinder_size(parts); 2219 1.19 martin i = NUMSEC(i, localsizemult, cylsize); 2220 1.1 dholland /* Adjust to start of slice if needed */ 2221 1.7 martin if ((i < min && (min - i) < localsizemult) || 2222 1.7 martin (i > min && (i - min) < localsizemult)) { 2223 1.7 martin i = min; 2224 1.1 dholland } 2225 1.7 martin if (max == 0 || i <= max) 2226 1.1 dholland break; 2227 1.1 dholland errmsg = msg_string(MSG_startoutsidedisk); 2228 1.1 dholland } 2229 1.7 martin free(label_msg); 2230 1.7 martin free(freespace); 2231 1.7 martin 2232 1.1 dholland return i; 2233 1.1 dholland } 2234 1.1 dholland 2235 1.1 dholland 2236 1.1 dholland /* Ask for a partition size, check bounds and do the needed roundups */ 2237 1.7 martin daddr_t 2238 1.25 martin getpartsize(struct disk_partitions *parts, daddr_t orig_start, 2239 1.25 martin daddr_t partstart, daddr_t dflt) 2240 1.1 dholland { 2241 1.7 martin char dsize[24], isize[24], max_size[24], maxpartc, valid_parts[4], 2242 1.7 martin *label_msg, *prompt, *head, *hint, *tail; 2243 1.7 martin const char *errmsg = NULL; 2244 1.19 martin daddr_t i, partend, diskend, localsizemult, max, max_r, dflt_r; 2245 1.7 martin struct disk_part_info info; 2246 1.7 martin part_id partn; 2247 1.7 martin 2248 1.19 martin diskend = parts->disk_start + parts->disk_size; 2249 1.25 martin max = parts->pscheme->max_free_space_at(parts, orig_start); 2250 1.25 martin max += orig_start - partstart; 2251 1.25 martin if (sizemult == 1) 2252 1.25 martin max--; /* with hugher scale proper rounding later will be ok */ 2253 1.7 martin 2254 1.7 martin /* We need to keep both the unrounded and rounded (_r) max and dflt */ 2255 1.7 martin dflt_r = (partstart + dflt) / sizemult - partstart / sizemult; 2256 1.7 martin if (max == dflt) 2257 1.7 martin max_r = dflt_r; 2258 1.7 martin else 2259 1.7 martin max_r = max / sizemult; 2260 1.32 rillig /* the partition may have been moved and now not fit any longer */ 2261 1.7 martin if (dflt > max) 2262 1.7 martin dflt = max; 2263 1.7 martin if (dflt_r > max_r) 2264 1.7 martin dflt_r = max_r; 2265 1.7 martin 2266 1.7 martin snprintf(max_size, sizeof max_size, "%" PRIu64, max_r); 2267 1.7 martin 2268 1.7 martin maxpartc = 'a' + parts->num_part -1; 2269 1.7 martin if (parts->num_part > 1) { 2270 1.7 martin snprintf(valid_parts, sizeof valid_parts, "a-%c", maxpartc); 2271 1.7 martin } else if (parts->num_part == 1) { 2272 1.7 martin snprintf(valid_parts, sizeof valid_parts, " %c", maxpartc); 2273 1.7 martin } else { 2274 1.7 martin strcpy(valid_parts, "---"); 2275 1.7 martin } 2276 1.7 martin 2277 1.7 martin const char *args[] = { valid_parts, max_size, multname }; 2278 1.7 martin hint = NULL; 2279 1.7 martin head = str_arg_subst(msg_string(MSG_label_size_head), 2280 1.7 martin __arraycount(args), args); 2281 1.7 martin if (parts->num_part) 2282 1.7 martin hint = str_arg_subst(msg_string(MSG_label_size_part_hint), 2283 1.7 martin __arraycount(args), args); 2284 1.7 martin tail = str_arg_subst(msg_string(MSG_label_size_tail), 2285 1.7 martin __arraycount(args), args); 2286 1.7 martin 2287 1.7 martin if (hint != NULL) 2288 1.7 martin asprintf(&label_msg, "%s\n%s\n\n%s", head, hint, tail); 2289 1.7 martin else 2290 1.7 martin asprintf(&label_msg, "%s\n\n%s", head, tail); 2291 1.7 martin free(head); free(hint); free(tail); 2292 1.1 dholland 2293 1.7 martin localsizemult = sizemult; 2294 1.7 martin i = -1; 2295 1.1 dholland for (;;) { 2296 1.7 martin snprintf(dsize, sizeof dsize, "%" PRIu64, dflt_r); 2297 1.7 martin 2298 1.7 martin if (errmsg != NULL && errmsg[0] != 0) 2299 1.7 martin asprintf(&prompt, "%s\n\n%s", errmsg, label_msg); 2300 1.7 martin else 2301 1.7 martin prompt = label_msg; 2302 1.7 martin msg_prompt_win(prompt, -1, 12, 70, -1, 2303 1.7 martin (dflt != 0) ? dsize : 0, isize, sizeof isize); 2304 1.7 martin if (prompt != label_msg) 2305 1.7 martin free(prompt); 2306 1.7 martin 2307 1.7 martin if (strcmp(isize, dsize) == 0) { 2308 1.7 martin free(label_msg); 2309 1.7 martin return dflt; 2310 1.7 martin } 2311 1.7 martin if (parts->num_part && isize[1] == '\0' && isize[0] >= 'a' && 2312 1.1 dholland isize[0] <= maxpartc) { 2313 1.1 dholland partn = isize[0] - 'a'; 2314 1.7 martin if (parts->pscheme->get_part_info(parts, partn, 2315 1.32 rillig &info)) { 2316 1.7 martin i = info.start - partstart -1; 2317 1.7 martin localsizemult = 1; 2318 1.7 martin max_r = max; 2319 1.7 martin } 2320 1.1 dholland } else if (atoi(isize) == -1) { 2321 1.7 martin i = max; 2322 1.1 dholland localsizemult = 1; 2323 1.7 martin max_r = max; 2324 1.1 dholland } else { 2325 1.7 martin i = parse_disk_pos(isize, &localsizemult, 2326 1.20 martin parts->bytes_per_sector, 2327 1.19 martin parts->pscheme->get_cylinder_size(parts), NULL); 2328 1.7 martin if (localsizemult != sizemult) 2329 1.7 martin max_r = max; 2330 1.7 martin } 2331 1.7 martin if (i < 0) { 2332 1.7 martin errmsg = msg_string(MSG_Invalid_numeric); 2333 1.7 martin continue; 2334 1.7 martin } else if (i > max_r) { 2335 1.7 martin errmsg = msg_string(MSG_Too_large); 2336 1.7 martin continue; 2337 1.1 dholland } 2338 1.1 dholland /* 2339 1.1 dholland * partend is aligned to a cylinder if localsizemult 2340 1.1 dholland * is not 1 sector 2341 1.1 dholland */ 2342 1.19 martin int cylsize = parts->pscheme->get_cylinder_size(parts); 2343 1.7 martin partend = NUMSEC((partstart + i*localsizemult) / localsizemult, 2344 1.19 martin localsizemult, cylsize); 2345 1.1 dholland /* Align to end-of-disk or end-of-slice if close enough */ 2346 1.19 martin if (partend > (diskend - sizemult) 2347 1.19 martin && partend < (diskend + sizemult)) 2348 1.19 martin partend = diskend; 2349 1.7 martin if (partend > (partstart + max - sizemult) 2350 1.7 martin && partend < (partstart + max + sizemult)) 2351 1.7 martin partend = partstart + max; 2352 1.1 dholland /* sanity checks */ 2353 1.19 martin if (partend > diskend) { 2354 1.19 martin partend = diskend; 2355 1.7 martin errmsg = msg_string(MSG_endoutsidedisk); 2356 1.7 martin continue; 2357 1.1 dholland } 2358 1.7 martin free(label_msg); 2359 1.1 dholland if (partend < partstart) 2360 1.1 dholland return 0; 2361 1.1 dholland return (partend - partstart); 2362 1.1 dholland } 2363 1.1 dholland /* NOTREACHED */ 2364 1.1 dholland } 2365 1.1 dholland 2366 1.1 dholland /* 2367 1.1 dholland * convert a string to a number of sectors, with a possible unit 2368 1.1 dholland * 150M = 150 Megabytes 2369 1.1 dholland * 2000c = 2000 cylinders 2370 1.1 dholland * 150256s = 150256 sectors 2371 1.7 martin * Without units, use the default (sizemult). 2372 1.7 martin * returns the raw input value, and the unit used. Caller needs to multiply! 2373 1.7 martin * On invalid inputs, returns -1. 2374 1.1 dholland */ 2375 1.7 martin daddr_t 2376 1.7 martin parse_disk_pos( 2377 1.7 martin const char *str, 2378 1.7 martin daddr_t *localsizemult, 2379 1.20 martin daddr_t bps, 2380 1.7 martin daddr_t cyl_size, 2381 1.7 martin bool *extend_this) 2382 1.1 dholland { 2383 1.7 martin daddr_t val; 2384 1.7 martin char *cp; 2385 1.7 martin bool mult_found; 2386 1.1 dholland 2387 1.1 dholland if (str[0] == '\0') { 2388 1.7 martin return -1; 2389 1.1 dholland } 2390 1.7 martin val = strtoull(str, &cp, 10); 2391 1.7 martin mult_found = false; 2392 1.7 martin if (extend_this) 2393 1.7 martin *extend_this = false; 2394 1.7 martin while (*cp != 0) { 2395 1.7 martin if (*cp == 'G' || *cp == 'g') { 2396 1.7 martin if (mult_found) 2397 1.7 martin return -1; 2398 1.20 martin *localsizemult = GIG / bps; 2399 1.7 martin goto next; 2400 1.1 dholland } 2401 1.7 martin if (*cp == 'M' || *cp == 'm') { 2402 1.7 martin if (mult_found) 2403 1.7 martin return -1; 2404 1.20 martin *localsizemult = MEG / bps; 2405 1.7 martin goto next; 2406 1.1 dholland } 2407 1.7 martin if (*cp == 'c' || *cp == 'C') { 2408 1.7 martin if (mult_found) 2409 1.7 martin return -1; 2410 1.19 martin *localsizemult = cyl_size; 2411 1.7 martin goto next; 2412 1.1 dholland } 2413 1.7 martin if (*cp == 's' || *cp == 'S') { 2414 1.7 martin if (mult_found) 2415 1.7 martin return -1; 2416 1.1 dholland *localsizemult = 1; 2417 1.7 martin goto next; 2418 1.7 martin } 2419 1.7 martin if (*cp == '+' && extend_this) { 2420 1.7 martin *extend_this = true; 2421 1.7 martin cp++; 2422 1.1 dholland break; 2423 1.1 dholland } 2424 1.7 martin 2425 1.1 dholland /* not a known unit */ 2426 1.7 martin return -1; 2427 1.7 martin 2428 1.7 martin next: 2429 1.7 martin mult_found = true; 2430 1.7 martin cp++; 2431 1.7 martin continue; 2432 1.1 dholland } 2433 1.7 martin if (*cp != 0) 2434 1.7 martin return -1; 2435 1.7 martin 2436 1.7 martin return val; 2437 1.1 dholland } 2438