diff --git a/lib/libdisk/chunk.c b/lib/libdisk/chunk.c index 0fbb754da837..96d73381794c 100644 --- a/lib/libdisk/chunk.c +++ b/lib/libdisk/chunk.c @@ -1,566 +1,568 @@ /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ #include __FBSDID("$FreeBSD$"); +#include +#include #include #include #include #include -#include #include #include "libdisk.h" struct chunk * New_Chunk(void) { struct chunk *c; c = malloc(sizeof *c); if (c != NULL) memset(c, 0, sizeof *c); return (c); } /* Is c2 completely inside c1 ? */ static int Chunk_Inside(const struct chunk *c1, const struct chunk *c2) { /* if c1 ends before c2 do */ if (c1->end < c2->end) return 0; /* if c1 starts after c2 do */ if (c1->offset > c2->offset) return 0; return 1; } static struct chunk * -Find_Mother_Chunk(struct chunk *chunks, u_long offset, u_long end, +Find_Mother_Chunk(struct chunk *chunks, daddr_t offset, daddr_t end, chunk_e type) { struct chunk *c1, *c2, ct; ct.offset = offset; ct.end = end; switch (type) { case whole: if (Chunk_Inside(chunks, &ct)) return chunks; case extended: for (c1 = chunks->part; c1; c1 = c1->next) { if (c1->type != type) continue; if (Chunk_Inside(c1, &ct)) return c1; } return 0; case freebsd: for (c1 = chunks->part; c1; c1 = c1->next) { if (c1->type == type) if (Chunk_Inside(c1, &ct)) return c1; if (c1->type != extended) continue; for (c2 = c1->part; c2; c2 = c2->next) if (c2->type == type && Chunk_Inside(c2, &ct)) return c2; } return 0; default: warn("Unsupported mother type in Find_Mother_Chunk"); return 0; } } void Free_Chunk(struct chunk *c1) { if(c1 == NULL) return; if(c1->private_data && c1->private_free) (*c1->private_free)(c1->private_data); if(c1->part != NULL) Free_Chunk(c1->part); if(c1->next != NULL) Free_Chunk(c1->next); if (c1->name != NULL) free(c1->name); if (c1->sname != NULL) free(c1->sname); free(c1); } struct chunk * Clone_Chunk(const struct chunk *c1) { struct chunk *c2; if(!c1) return NULL; c2 = New_Chunk(); if (c2 == NULL) return NULL; *c2 = *c1; if (c1->private_data && c1->private_clone) c2->private_data = c2->private_clone(c2->private_data); c2->name = strdup(c2->name); if (c2->sname != NULL) c2->sname = strdup(c2->sname); c2->next = Clone_Chunk(c2->next); c2->part = Clone_Chunk(c2->part); return c2; } int -Insert_Chunk(struct chunk *c2, u_long offset, u_long size, const char *name, +Insert_Chunk(struct chunk *c2, daddr_t offset, daddr_t size, const char *name, chunk_e type, int subtype, u_long flags, const char *sname) { struct chunk *ct,*cs; /* We will only insert into empty spaces */ if (c2->type != unused) return __LINE__; ct = New_Chunk(); if (ct == NULL) return __LINE__; ct->disk = c2->disk; ct->offset = offset; ct->size = size; ct->end = offset + size - 1; ct->type = type; if (sname != NULL) ct->sname = strdup(sname); ct->name = strdup(name); ct->subtype = subtype; ct->flags = flags; if (!Chunk_Inside(c2, ct)) { Free_Chunk(ct); return __LINE__; } if (type == freebsd || type == extended) { cs = New_Chunk(); if (cs == NULL) return __LINE__; cs->disk = c2->disk; cs->offset = offset; cs->size = size; cs->end = offset + size - 1; cs->type = unused; if (sname != NULL) cs->sname = strdup(sname); cs->name = strdup("-"); ct->part = cs; } /* Make a new chunk for any trailing unused space */ if (c2->end > ct->end) { cs = New_Chunk(); if (cs == NULL) return __LINE__; *cs = *c2; cs->disk = c2->disk; cs->offset = ct->end + 1; cs->size = c2->end - ct->end; if (c2->sname != NULL) cs->sname = strdup(c2->sname); if (c2->name) cs->name = strdup(c2->name); c2->next = cs; c2->size -= c2->end - ct->end; c2->end = ct->end; } /* If no leading unused space just occupy the old chunk */ if (c2->offset == ct->offset) { c2->sname = ct->sname; c2->name = ct->name; c2->type = ct->type; c2->part = ct->part; c2->subtype = ct->subtype; c2->flags = ct->flags; ct->sname = NULL; ct->name = NULL; ct->part = 0; Free_Chunk(ct); return 0; } /* else insert new chunk and adjust old one */ c2->end = ct->offset - 1; c2->size -= ct->size; ct->next = c2->next; c2->next = ct; return 0; } int -Add_Chunk(struct disk *d, long offset, u_long size, const char *name, +Add_Chunk(struct disk *d, daddr_t offset, daddr_t size, const char *name, chunk_e type, int subtype, u_long flags, const char *sname) { struct chunk *c1, *c2, ct; - u_long end = offset + size - 1; + daddr_t end = offset + size - 1; ct.offset = offset; ct.end = end; ct.size = size; if (type == whole) { d->chunks = c1 = New_Chunk(); if (c1 == NULL) return __LINE__; c2 = c1->part = New_Chunk(); if (c2 == NULL) return __LINE__; c2->disk = c1->disk = d; c2->offset = c1->offset = offset; c2->size = c1->size = size; c2->end = c1->end = end; c1->sname = strdup(sname); c2->sname = strdup("-"); c1->name = strdup(name); c2->name = strdup("-"); c1->type = type; c2->type = unused; c1->flags = flags; c1->subtype = subtype; return 0; } c1 = 0; /* PLATFORM POLICY BEGIN ------------------------------------- */ switch(platform) { case p_i386: case p_amd64: switch (type) { case fat: case mbr: case extended: case freebsd: c1 = Find_Mother_Chunk(d->chunks, offset, end, whole); break; case part: c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd); break; default: return(-1); } break; case p_ia64: switch (type) { case freebsd: subtype = 0xa5; /* FALL THROUGH */ case fat: case efi: case mbr: c1 = Find_Mother_Chunk(d->chunks, offset, end, whole); break; case part: c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd); if (!c1) c1 = Find_Mother_Chunk(d->chunks, offset, end, whole); break; default: return (-1); } break; case p_pc98: switch (type) { case fat: case pc98: case freebsd: c1 = Find_Mother_Chunk(d->chunks, offset, end, whole); break; case part: c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd); break; default: return(-1); } break; case p_sparc64: case p_alpha: switch (type) { case freebsd: c1 = Find_Mother_Chunk(d->chunks, offset, end, whole); break; case part: c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd); break; default: return(-1); } break; default: return (-1); } /* PLATFORM POLICY END ---------------------------------------- */ if(!c1) return __LINE__; for(c2 = c1->part; c2; c2 = c2->next) { if (c2->type != unused) continue; if(!Chunk_Inside(c2, &ct)) continue; /* PLATFORM POLICY BEGIN ------------------------------------- */ if (platform == p_sparc64) { offset = Prev_Cyl_Aligned(d, offset); size = Next_Cyl_Aligned(d, size); } else if (platform == p_i386 || platform == p_pc98 || platform == p_amd64) { if (type != freebsd) break; if (!(flags & CHUNK_ALIGN)) break; if (offset == d->chunks->offset && end == d->chunks->end) break; /* Round down to prev cylinder */ offset = Prev_Cyl_Aligned(d,offset); /* Stay inside the parent */ if (offset < c2->offset) offset = c2->offset; /* Round up to next cylinder */ offset = Next_Cyl_Aligned(d, offset); /* Keep one track clear in front of parent */ if (offset == c1->offset) offset = Next_Track_Aligned(d, offset + 1); /* Work on the (end+1) */ size += offset; /* Round up to cylinder */ size = Next_Cyl_Aligned(d, size); /* Stay inside parent */ if ((size-1) > c2->end) size = c2->end + 1; /* Round down to cylinder */ size = Prev_Cyl_Aligned(d, size); /* Convert back to size */ size -= offset; } break; /* PLATFORM POLICY END ------------------------------------- */ } if (c2 == NULL) return (__LINE__); return Insert_Chunk(c2, offset, size, name, type, subtype, flags, sname); } char * ShowChunkFlags(struct chunk *c) { static char ret[10]; int i = 0; if (c->flags & CHUNK_ACTIVE) ret[i++] = 'A'; if (c->flags & CHUNK_ALIGN) ret[i++] = '='; if (c->flags & CHUNK_IS_ROOT) ret[i++] = 'R'; ret[i++] = '\0'; return ret; } static void -Print_Chunk(struct chunk *c1,int offset) +Print_Chunk(struct chunk *c1, int offset) { int i; if (!c1) return; for (i = 0; i < offset - 2; i++) putchar(' '); for (; i < offset; i++) putchar('-'); putchar('>'); for (; i < 10; i++) putchar(' '); #ifndef __ia64__ printf("%p ", c1); #endif - printf("%8ld %8lu %8lu %-8s %-16s %-8s 0x%02x %s", c1->offset, - c1->size, c1->end, c1->name, c1->sname, chunk_name(c1->type), - c1->subtype, ShowChunkFlags(c1)); + printf("%8jd %8jd %8jd %-8s %-16s %-8s 0x%02x %s", + (intmax_t)c1->offset, (intmax_t)c1->size, (intmax_t)c1->end, + c1->name, c1->sname, chunk_name(c1->type), c1->subtype, + ShowChunkFlags(c1)); putchar('\n'); Print_Chunk(c1->part, offset + 2); Print_Chunk(c1->next, offset); } void Debug_Chunk(struct chunk *c1) { - Print_Chunk(c1,2); + Print_Chunk(c1, 2); } int Delete_Chunk(struct disk *d, struct chunk *c) { - return(Delete_Chunk2(d, c, 0)); + return (Delete_Chunk2(d, c, 0)); } int Delete_Chunk2(struct disk *d, struct chunk *c, int rflags) { struct chunk *c1, *c2, *c3; - u_long offset = c->offset; + daddr_t offset = c->offset; switch (c->type) { case whole: case unused: return 1; case extended: c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole); break; case part: c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd); #ifdef __ia64__ if (c1 == NULL) c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole); #endif break; default: c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended); if (c1 == NULL) c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole); break; } if (c1 == NULL) return 1; for (c2 = c1->part; c2; c2 = c2->next) { if (c2 == c) { c2->type = unused; c2->subtype = 0; c2->flags = 0; if (c2->sname != NULL) free(c2->sname); c2->sname = strdup("-"); free(c2->name); c2->name = strdup("-"); Free_Chunk(c2->part); c2->part =0; goto scan; } } return 1; scan: /* * Collapse multiple unused elements together, and attempt * to extend the previous chunk into the freed chunk. * * We only extend non-unused elements which are marked * for newfs (we can't extend working filesystems), and * only if we are called with DELCHUNK_RECOVER. */ for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type != unused) { if (c2->offset + c2->size != offset || (rflags & DELCHUNK_RECOVER) == 0 || (c2->flags & CHUNK_NEWFS) == 0) { continue; } /* else extend into free area */ } if (!c2->next) continue; if (c2->next->type != unused) continue; c3 = c2->next; c2->size += c3->size; c2->end = c3->end; c2->next = c3->next; c3->next = 0; Free_Chunk(c3); goto scan; } Fixup_Names(d); return 0; } #if 0 int Collapse_Chunk(struct disk *d, struct chunk *c1) { struct chunk *c2, *c3; if (c1->next && Collapse_Chunk(d, c1->next)) return 1; if (c1->type == unused && c1->next && c1->next->type == unused) { c3 = c1->next; c1->size += c3->size; c1->end = c3->end; c1->next = c3->next; c3->next = 0; Free_Chunk(c3); return 1; } c3 = c1->part; if (!c3) return 0; if (Collapse_Chunk(d, c1->part)) return 1; if (c1->type == whole) return 0; if (c3->type == unused && c3->size == c1->size) { Delete_Chunk(d, c1); return 1; } if (c3->type == unused) { c2 = New_Chunk(); if (c2 == NULL) barfout(1, "malloc failed"); *c2 = *c1; c1->next = c2; c1->disk = d; c1->sname = strdup("-"); c1->name = strdup("-"); c1->part = 0; c1->type = unused; c1->flags = 0; c1->subtype = 0; c1->size = c3->size; c1->end = c3->end; c2->offset += c1->size; c2->size -= c1->size; c2->part = c3->next; c3->next = 0; Free_Chunk(c3); return 1; } for (c2 = c3; c2->next; c2 = c2->next) c3 = c2; if (c2 && c2->type == unused) { c3->next = 0; c2->next = c1->next; c1->next = c2; c1->size -= c2->size; c1->end -= c2->size; return 1; } return 0; } #endif diff --git a/lib/libdisk/create_chunk.c b/lib/libdisk/create_chunk.c index d3625b931332..c65b8f3f3390 100644 --- a/lib/libdisk/create_chunk.c +++ b/lib/libdisk/create_chunk.c @@ -1,275 +1,275 @@ /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #ifdef PC98 #include #else #include #endif #include #include #include #include #include #include #include "libdisk.h" struct chunk *New_Chunk(void); static int Fixup_FreeBSD_Names(struct chunk *c) { struct chunk *c1, *c3; uint j; if (!strcmp(c->name, "X")) return 0; /* reset all names to "X" */ for (c1 = c->part; c1; c1 = c1->next) { c1->oname = c1->name; c1->name = malloc(12); if (!c1->name) return -1; strcpy(c1->name,"X"); } /* Allocate the first swap-partition we find */ for (c1 = c->part; c1; c1 = c1->next) { if (c1->type == unused) continue; if (c1->subtype != FS_SWAP) continue; sprintf(c1->name, "%s%c", c->name, SWAP_PART + 'a'); break; } /* Allocate the first root-partition we find */ for (c1 = c->part; c1; c1 = c1->next) { if (c1->type == unused) continue; if (!(c1->flags & CHUNK_IS_ROOT)) continue; sprintf(c1->name, "%s%c", c->name, 0 + 'a'); break; } /* Try to give them the same as they had before */ for (c1 = c->part; c1; c1 = c1->next) { if (strcmp(c1->name, "X")) continue; for (c3 = c->part; c3 ; c3 = c3->next) if (c1 != c3 && !strcmp(c3->name, c1->oname)) goto newname; strcpy(c1->name, c1->oname); newname: ; } /* Allocate the rest sequentially */ for (c1 = c->part; c1; c1 = c1->next) { const char order[] = "defghab"; if (c1->type == unused) continue; if (strcmp("X", c1->name)) continue; for (j = 0; j < strlen(order); j++) { sprintf(c1->name, "%s%c", c->name, order[j]); for (c3 = c->part; c3 ; c3 = c3->next) if (c1 != c3 && !strcmp(c3->name, c1->name)) goto match; break; match: strcpy(c1->name, "X"); continue; } } for (c1 = c->part; c1; c1 = c1->next) { free(c1->oname); c1->oname = 0; } return 0; } #ifndef PC98 static int Fixup_Extended_Names(struct chunk *c) { struct chunk *c1; int j = 5; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type == unused) continue; free(c1->name); c1->name = malloc(12); if (!c1->name) return -1; sprintf(c1->name, "%ss%d", c->disk->chunks->name, j++); if (c1->type == freebsd) if (Fixup_FreeBSD_Names(c1) != 0) return -1; } return 0; } #endif int Fixup_Names(struct disk *d) { struct chunk *c1, *c2; #if defined(__i386__) || defined(__ia64__) || defined(__amd64__) struct chunk *c3; int j, max; #endif c1 = d->chunks; for (c2 = c1->part; c2 ; c2 = c2->next) { if (c2->type == unused) continue; if (strcmp(c2->name, "X")) continue; #if defined(__i386__) || defined(__ia64__) || defined(__amd64__) c2->oname = malloc(12); if (!c2->oname) return -1; #ifdef __ia64__ max = d->gpt_size; #else max = NDOSPART; #endif for (j = 1; j <= max; j++) { #ifdef __ia64__ sprintf(c2->oname, "%s%c%d", c1->name, (c1->type == whole) ? 'p' : 's', j); #else sprintf(c2->oname, "%ss%d", c1->name, j); #endif for (c3 = c1->part; c3; c3 = c3->next) if (c3 != c2 && !strcmp(c3->name, c2->oname)) goto match; free(c2->name); c2->name = c2->oname; c2->oname = 0; break; match: continue; } if (c2->oname) free(c2->oname); #else free(c2->name); c2->name = strdup(c1->name); #endif /*__i386__*/ } for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == freebsd) Fixup_FreeBSD_Names(c2); #ifndef PC98 else if (c2->type == extended) Fixup_Extended_Names(c2); #endif } return 0; } int -Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, +Create_Chunk(struct disk *d, daddr_t offset, daddr_t size, chunk_e type, int subtype, u_long flags, const char *sname) { int i; #ifndef __ia64__ if (!(flags & CHUNK_FORCE_ALL)) { - u_long l; + daddr_t l; #ifdef PC98 /* Never use the first cylinder */ if (!offset) { offset += (d->bios_sect * d->bios_hd); size -= (d->bios_sect * d->bios_hd); } #else /* Never use the first track */ if (!offset) { offset += d->bios_sect; size -= d->bios_sect; } #endif /* PC98 */ /* Always end on cylinder boundary */ - l = (offset+size) % (d->bios_sect * d->bios_hd); + l = (offset + size) % (d->bios_sect * d->bios_hd); size -= l; } #endif i = Add_Chunk(d, offset, size, "X", type, subtype, flags, sname); Fixup_Names(d); return i; } struct chunk * -Create_Chunk_DWIM(struct disk *d, struct chunk *parent, u_long size, +Create_Chunk_DWIM(struct disk *d, struct chunk *parent, daddr_t size, chunk_e type, int subtype, u_long flags) { int i; struct chunk *c1; - long offset; + daddr_t offset; if (!parent) parent = d->chunks; if (parent->type == freebsd && type == part && parent->part == NULL) { c1 = New_Chunk(); if (c1 == NULL) return (NULL); c1->disk = parent->disk; c1->offset = parent->offset; c1->size = parent->size; c1->end = parent->offset + parent->size - 1; c1->type = unused; if (parent->sname != NULL) c1->sname = strdup(parent->sname); c1->name = strdup("-"); parent->part = c1; } for (c1 = parent->part; c1; c1 = c1->next) { if (c1->type != unused) continue; if (c1->size < size) continue; offset = c1->offset; goto found; } return 0; found: i = Add_Chunk(d, offset, size, "X", type, subtype, flags, "-"); if (i) return 0; Fixup_Names(d); for (c1 = parent->part; c1; c1 = c1->next) if (c1->offset == offset) return c1; /* barfout(1, "Serious internal trouble"); */ return 0; } diff --git a/lib/libdisk/libdisk.3 b/lib/libdisk/libdisk.3 index 6d088b3f5b44..341bb4f51a27 100644 --- a/lib/libdisk/libdisk.3 +++ b/lib/libdisk/libdisk.3 @@ -1,331 +1,331 @@ .\" .\" Copyright (c) 1996 Joerg Wunsch .\" .\" All rights reserved. .\" .\" This program is free software. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" " .Dd March 15, 1996 .Dt LIBDISK 3 .Os .Sh NAME .Nm Open_Disk , .Nm Free_Disk , .Nm Debug_Disk , .Nm Set_Bios_Geom , .Nm Delete_Chunk , .Nm Collapse_Disk , .Nm Collapse_Chunk , .Nm Create_Chunk , .Nm All_FreeBSD , .Nm CheckRules , .Nm Disk_Names , .Nm Set_Boot_Mgr , .Nm Set_Boot_Blocks , .Nm Write_Disk , .Nm Cyl_Aligned , .Nm Next_Cyl_Aligned , .Nm Prev_Cyl_Aligned , .Nm Track_Aligned , .Nm Next_Track_Aligned , .Nm Prev_Track_Aligned , .Nm Create_Chunk_DWIM , .Nm MakeDev , .Nm MakeDevDisk , .Nm ShowChunkFlags , .Nm chunk_name , .Nm slice_type_name .Nd library interface to slice and partition labels .Sh LIBRARY .Lb libdisk .Sh SYNOPSIS .In sys/types.h .In libdisk.h .Pp .Ft struct disk * .Fn Open_Disk "const char *devname" .Ft void .Fn Free_Disk "struct disk *disk" .Ft void .Fn Debug_Disk "struct disk *disk" .Ft void .Fn Set_Bios_Geom "struct disk *disk" "u_long cyl" "u_long heads" "u_long sects" .Ft int .Fn Delete_Chunk "struct disk *disk" "struct chunk *" .Ft void .Fn Collapse_Disk "struct disk *disk" .Ft int .Fn Collapse_Chunk "struct disk *disk" "struct chunk *chunk" .Ft int -.Fn Create_Chunk "struct disk *disk" "u_long offset" "u_long size" "chunk_e type" "int subtype" "u_long flags" +.Fn Create_Chunk "struct disk *disk" "daddr_t offset" "daddr_t size" "chunk_e type" "int subtype" "u_long flags" .Ft void .Fn All_FreeBSD "struct disk *d" "int force_all" .Ft char * .Fn CheckRules "struct disk *" .Ft char ** .Fn Disk_Names "void" .Ft void .Fn Set_Boot_Mgr "struct disk *d" "const u_char *bootmgr" "const size_t bootmgr_size" .Ft int .Fn Set_Boot_Blocks "struct disk *d" "const u_char *boot1" "const u_char *boot2" .Ft int .Fn Write_Disk "struct disk *d" .Ft int -.Fn Cyl_Aligned "struct disk *d" "u_long offset" -.Ft u_long -.Fn Next_Cyl_Aligned "struct disk *d" "u_long offset" -.Ft u_long -.Fn Prev_Cyl_Aligned "struct disk *d" "u_long offset" +.Fn Cyl_Aligned "struct disk *d" "daddr_t offset" +.Ft daddr_t +.Fn Next_Cyl_Aligned "struct disk *d" "daddr_t offset" +.Ft daddr_t +.Fn Prev_Cyl_Aligned "struct disk *d" "daddr_t offset" .Ft int -.Fn Track_Aligned "struct disk *d" "u_long offset" -.Ft u_long -.Fn Next_Track_Aligned "struct disk *d" "u_long offset" -.Ft u_long -.Fn Prev_Track_Aligned "struct disk *d" "u_long offset" +.Fn Track_Aligned "struct disk *d" "daddr_t offset" +.Ft daddr_t +.Fn Next_Track_Aligned "struct disk *d" "daddr_t offset" +.Ft daddr_t +.Fn Prev_Track_Aligned "struct disk *d" "daddr_t offset" .Ft struct chunk * -.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "u_long size" "chunk_e type" "int subtype" "u_long flags" +.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "daddr_t size" "chunk_e type" "int subtype" "u_long flags" .Ft int .Fn MakeDev "struct chunk *c" "const char *path" .Ft int .Fn MakeDevDisk "struct disk *d" "const char *path" .Ft char * .Fn ShowChunkFlags "struct chunk *c" .Ft const char * .Fn chunk_name "chunk_e type" .Ft const char * .Fn slice_type_name "int type" "int subtype" .Sh DESCRIPTION The .Nm libdisk library provides an interface to the low-level disk slice and partition labels. Most functions operate with arguments of the types .Ql struct disk , or .Ql struct chunk . .Pp While both types are mostly opaque to the programmer, the internal structure is mentioned below for the sake of completeness. .Bd -literal -offset indent struct disk { char *name; u_long flags; u_long bios_cyl; u_long bios_hd; u_long bios_sect; u_char *bootmgr; u_char *boot1; u_char *boot2; struct chunk *chunks; u_long sector_size; }; .Ed The only flag value by now is .Ql DISK_ON_TRACK , meaning that this disk is handled by the On-Track Disk Manager. .Pp .Bd -literal -offset indent struct chunk { struct chunk *next; struct chunk *part; struct disk *disk; - long offset; - u_long size; - u_long end; + daddr_t offset; + daddr_t size; + daddr_t end; char *name; char *oname; chunk_e type; int subtype; u_long flags; void (*private_free)(void*); void *(*private_clone)(void*); void *private_data; }; .Ed The .Ql type field can be one of the following values: .Ql whole, unknown, fat, freebsd, extended, part, unused . .Pp These are the valid .Ql flag values for a .Ql struct chunk . .Bl -tag -offset indent -width CHUNK_BSD_COMPATXX .It CHUNK_PAST_1024 This chunk cannot be booted from because it extends past cylinder 1024. .It CHUNK_BSD_COMPAT This chunk is in the .Bx Ns -compatibility , and has a short name too, i.e.\& .Ql wd0s4f -> wd0f . .It CHUNK_ALIGN This chunk should be aligned. .It CHUNK_IS_ROOT This .Ql part is a rootfs, allocate partition .Sq a . .It CHUNK_ACTIVE This is the active slice in the MBR. .It CHUNK_FORCE_ALL Force a dedicated disk for .Fx , bypassing all BIOS geometry considerations. .El .Pp The .Ql private_data , .Ql private_free , and .Ql private_clone fields are for data private to the application, and the management thereof. If the functions are not provided, no storage management is done, cloning will just copy the pointer and freeing will just forget it. .Pp .Fn Open_Disk will open the named disk, and return populated tree. .Pp .Fn Free_Disk frees a tree made with .Fn Open_Disk or .Fn Clone_Disk . .Pp .Fn Debug_Disk prints the content of the tree to .Dv stdout . .Pp .Fn Set_Bios_Geom sets the geometry the bios uses. .Pp .Fn Delete_Chunk frees a chunk of disk_space. .Pp .Fn Collapse_Disk and .Fn Collapse_Chunk are experimental, do not use. .Pp .Fn Create_Chunk creates a chunk with the specified parameters. .Pp .Fn All_FreeBSD makes one .Fx chunk covering the entire disk; if .Ql force_all is set, bypass all BIOS geometry considerations. .Pp .Fn CheckRules returns .Ql char* to warnings about broken design rules in this disklayout. .Pp .Fn Disk_Names returns .Ql char** with all disk's names (wd0, wd1 ...). You must free each pointer, as well as the array by hand. .Pp .Fn Set_Boot_Mgr sets this boot-manager for use on this disk. Gets written when .Fn Write_Disk is called. .Pp .Fn Set_Boot_Blocks sets the boot-blocks for use on this disk. Gets written when .Fn Write_Disk is called. .Pp .Fn Write_Disk writes all the MBRs, disklabels, bootblocks and boot managers. .Pp .Fn Cyl_Aligned checks if .Ql offset is aligned on a cylinder according to the BIOS geometry. .Pp .Fn Next_Cyl_Aligned rounds .Ql offset up to next cylinder according to the BIOS geometry. .Pp .Fn Prev_Cyl_Aligned rounds .Ql offset down to previous cylinder according to the BIOS geometry. .Pp .Fn Track_Aligned checks if .Ql offset is aligned on a track according to the BIOS geometry. .Pp .Fn Next_Track_Aligned rounds .Ql offset up to next track according to the BIOS geometry. .Pp .Fn Prev_Track_Aligned checks if .Ql offset is aligned on a track according to the BIOS geometry. .Pp .Fn Create_Chunk_DWIM creates a partition inside the given parent of the given size, and returns a pointer to it. The first unused chunk big enough is used. .Pp .Fn MakeDev makes the device nodes for this chunk. .Pp .Fn MakeDevDisk makes the device nodes for all chunks on this disk. .Pp .Fn ShowChunkFlags returns a string to show flags. .Pp The .Fn chunk_name function takes the enumerated chunk type and returns its name. .Fn chunk_name replaces the old external array .Va chunk_n . .Pp .Fn slice_type_name returns the name strings associated with the specified .Ql type . .Ql subtype . If .Fn slice_type_name returns "unknown" for slices it isn't familiar with. .Sh AUTHORS .An -nosplit The .Nm libdisk library was written by .An Poul-Henning Kamp . .Pp This manual page was written by .An J\(:org Wunsch . diff --git a/lib/libdisk/libdisk.h b/lib/libdisk/libdisk.h index ac97d898b791..32ae5e7239fd 100644 --- a/lib/libdisk/libdisk.h +++ b/lib/libdisk/libdisk.h @@ -1,360 +1,360 @@ /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * * $FreeBSD$ * */ /* #define DEBUG 1 */ /* You can define a particular architecture here if you are debugging. */ /* #define P_DEBUG p_sparc64 */ #define MAX_NO_DISKS 32 /* Max # of disks Disk_Names() will return */ #define MAX_SEC_SIZE 2048 /* maximum sector size that is supported */ #define MIN_SEC_SIZE 512 /* the sector size to end sensing at */ enum platform { p_any, /* for debugging ! */ p_alpha, p_i386, p_pc98, p_sparc64, p_ia64, p_ppc, p_amd64 }; extern const enum platform platform; typedef enum { whole, unknown, sun, pc98, mbr, gpt, efi, fat, freebsd, extended, part, spare, unused } chunk_e; __BEGIN_DECLS #ifndef __ia64__ struct disk { char *name; u_long bios_cyl; u_long bios_hd; u_long bios_sect; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *bootmgr; size_t bootmgr_size; #endif u_char *boot1; #if defined(__i386__) || defined(__amd64__) /* the i386 needs extra help... */ u_char *boot2; #endif struct chunk *chunks; u_long sector_size; /* media sector size, a power of 2 */ }; #else /* !__ia64__ */ struct disk { char *name; struct chunk *chunks; u_long media_size; u_long sector_size; u_long lba_start; u_long lba_end; u_int gpt_size; /* Number of entries */ }; #endif struct chunk { struct chunk *next; struct chunk *part; struct disk *disk; - long offset; - u_long size; - u_long end; + daddr_t offset; + daddr_t size; + daddr_t end; char *sname; /* PC98 field */ char *name; char *oname; /* Used during Fixup_Names() to avoid renaming more than * absolutely needed. */ chunk_e type; int subtype; u_long flags; void (*private_free)(void*); void *(*private_clone)(void*); void *private_data; /* For data private to the application, and the management * thereof. If the functions are not provided, no storage * management is done, Cloning will just copy the pointer * and freeing will just forget it. */ }; /* * flags: * * ALIGN - This chunk should be aligned * IS_ROOT - This 'part' is a rootfs, allocate 'a' * ACTIVE - This is the active slice in the MBR * FORCE_ALL - Force a dedicated disk for FreeBSD, bypassing * all BIOS geometry considerations * AUTO_SIZE - This chunk was auto-sized and can fill-out a * following chunk if the following chunk is deleted. * NEWFS - newfs pending, used to enable auto-resizing on * delete (along with AUTO_SIZE). */ #define CHUNK_ALIGN 0x0008 #define CHUNK_IS_ROOT 0x0010 #define CHUNK_ACTIVE 0x0020 #define CHUNK_FORCE_ALL 0x0040 #define CHUNK_AUTO_SIZE 0x0080 #define CHUNK_NEWFS 0x0100 #define CHUNK_HAS_INDEX 0x0200 #define CHUNK_ITOF(i) ((i & 0xFFFF) << 16) #define CHUNK_FTOI(f) ((f >> 16) & 0xFFFF) #define DELCHUNK_NORMAL 0x0000 #define DELCHUNK_RECOVER 0x0001 const char *chunk_name(chunk_e); const char * slice_type_name(int, int); /* "chunk_n" for subtypes too */ struct disk * Open_Disk(const char *); /* Will open the named disk, and return populated tree. */ void Free_Disk(struct disk *); /* Free a tree made with Open_Disk() or Clone_Disk() */ void Debug_Disk(struct disk *); /* Print the content of the tree to stdout */ void Set_Bios_Geom(struct disk *, u_long, u_long, u_long); /* Set the geometry the bios uses. */ void Sanitize_Bios_Geom(struct disk *); /* Set the bios geometry to something sane */ int -Insert_Chunk(struct chunk *, u_long, u_long, const char *, chunk_e, int, +Insert_Chunk(struct chunk *, daddr_t, daddr_t, const char *, chunk_e, int, u_long, const char *); int Delete_Chunk2(struct disk *, struct chunk *, int); /* Free a chunk of disk_space modified by the passed flags. */ int Delete_Chunk(struct disk *, struct chunk *); /* Free a chunk of disk_space */ void Collapse_Disk(struct disk *); /* Experimental, do not use. */ int Collapse_Chunk(struct disk *, struct chunk *); /* Experimental, do not use. */ int -Create_Chunk(struct disk *, u_long, u_long, chunk_e, int, u_long, const char *); +Create_Chunk(struct disk *, daddr_t, daddr_t, chunk_e, int, u_long, const char *); /* Create a chunk with the specified paramters */ void All_FreeBSD(struct disk *, int); /* * Make one FreeBSD chunk covering the entire disk; * if force_all is set, bypass all BIOS geometry * considerations. */ char * CheckRules(const struct disk *); /* Return char* to warnings about broken design rules in this disklayout */ char ** Disk_Names(void); /* * Return char** with all disk's names (wd0, wd1 ...). You must free * each pointer, as well as the array by hand */ #ifdef PC98 void Set_Boot_Mgr(struct disk *, const u_char *, const size_t, const u_char *, const size_t); #else void Set_Boot_Mgr(struct disk *, const u_char *, const size_t); #endif /* * Use this boot-manager on this disk. Gets written when Write_Disk() * is called */ int Set_Boot_Blocks(struct disk *, const u_char *, const u_char *); /* * Use these boot-blocks on this disk. Gets written when Write_Disk() * is called. Returns nonzero upon failure. */ int Write_Disk(const struct disk *); /* Write all the MBRs, disklabels, bootblocks and boot managers */ -u_long -Next_Cyl_Aligned(const struct disk *, u_long); +daddr_t +Next_Cyl_Aligned(const struct disk *, daddr_t); /* Round offset up to next cylinder according to the bios-geometry */ -u_long -Prev_Cyl_Aligned(const struct disk *, u_long); +daddr_t +Prev_Cyl_Aligned(const struct disk *, daddr_t); /* Round offset down to previous cylinder according to the bios-geometry */ int -Track_Aligned(const struct disk *, u_long); +Track_Aligned(const struct disk *, daddr_t); /* Check if offset is aligned on a track according to the bios geometry */ -u_long -Next_Track_Aligned(const struct disk *, u_long); +daddr_t +Next_Track_Aligned(const struct disk *, daddr_t); /* Round offset up to next track according to the bios-geometry */ -u_long -Prev_Track_Aligned(const struct disk *, u_long); +daddr_t +Prev_Track_Aligned(const struct disk *, daddr_t); /* Check if offset is aligned on a track according to the bios geometry */ struct chunk * -Create_Chunk_DWIM(struct disk *, struct chunk *, u_long, chunk_e, int, +Create_Chunk_DWIM(struct disk *, struct chunk *, daddr_t, chunk_e, int, u_long); /* * This one creates a partition inside the given parent of the given * size, and returns a pointer to it. The first unused chunk big * enough is used. */ char * ShowChunkFlags(struct chunk *); /* Return string to show flags. */ /* * Implementation details >>> DO NOT USE <<< */ struct disklabel; void Fill_Disklabel(struct disklabel *, const struct disk *, const struct chunk *); void Debug_Chunk(struct chunk *); void Free_Chunk(struct chunk *); struct chunk *Clone_Chunk(const struct chunk *); -int Add_Chunk(struct disk *, long, u_long, const char *, chunk_e, int, u_long, - const char *); +int Add_Chunk(struct disk *, daddr_t, daddr_t, const char *, chunk_e, int, + u_long, const char *); void *read_block(int, daddr_t, u_long); int write_block(int, daddr_t, const void *, u_long); struct disklabel *read_disklabel(int, daddr_t, u_long); struct disk *Int_Open_Disk(const char *, char *); int Fixup_Names(struct disk *); int MakeDevChunk(const struct chunk *, const char *); __END_DECLS #define dprintf printf /* TODO * * Need an error string mechanism from the functions instead of warn() * * Make sure only FreeBSD start at offset==0 * * Collapse must align. * * Make Write_Disk(struct disk*) * * Consider booting from OnTrack'ed disks. * * Get Bios-geom, ST506 & OnTrack from driver (or otherwise) * * Make Create_DWIM(). * * Make Is_Unchanged(struct disk *d1, struct chunk *c1) * * don't rename slices unless we have to * *Sample output from tst01: * * Debug_Disk(wd0) flags=0 bios_geom=0/0/0 * >> 0x3d040 0 1411200 1411199 wd0 0 whole 0 0 * >>>> 0x3d080 0 960120 960119 wd0s1 3 freebsd 0 8 * >>>>>> 0x3d100 0 40960 40959 wd0s1a 5 part 0 0 * >>>>>> 0x3d180 40960 131072 172031 wd0s1b 5 part 0 0 * >>>>>> 0x3d1c0 172032 409600 581631 wd0s1e 5 part 0 0 * >>>>>> 0x3d200 581632 378488 960119 wd0s1f 5 part 0 0 * >>>> 0x3d140 960120 5670 965789 wd0s2 4 extended 0 8 * >>>>>> 0x3d2c0 960120 63 960182 - 6 unused 0 0 * >>>>>> 0x3d0c0 960183 5607 965789 wd0s5 2 fat 0 8 * >>>> 0x3d280 965790 1890 967679 wd0s3 1 foo -2 8 * >>>> 0x3d300 967680 443520 1411199 wd0s4 3 freebsd 0 8 * >>>>>> 0x3d340 967680 443520 1411199 wd0s4a 5 part 0 0 * * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ * level chunkptr start size end name type subtype flags * * Underlying data structure: * * Legend: * --> part * | * v next * * --> --> * | | * | v * | * | | * | v * | * | | * | v * | * | * v * --> * | | * | v * | * | * v * * | * v * --> * * */ diff --git a/lib/libdisk/open_disk.c b/lib/libdisk/open_disk.c index 99abba500eeb..b0d4ac73aef8 100644 --- a/lib/libdisk/open_disk.c +++ b/lib/libdisk/open_disk.c @@ -1,278 +1,278 @@ /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libdisk.h" #include #include #include #ifdef DEBUG #define DPRINT(x) warn x #define DPRINTX(x) warnx x #else #define DPRINT(x) #define DPRINTX(x) #endif struct disk * Int_Open_Disk(const char *name, char *conftxt) { struct disk *d; int i; char *p, *q, *r, *a, *b, *n, *t, *sn; - off_t o, len, off; + daddr_t o, len, off; u_int l, s, ty, sc, hd, alt; - off_t lo[10]; + daddr_t lo[10]; for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) { if (*p == '\n') p++; a = strsep(&p, " "); if (strcmp(a, "0")) continue; a = strsep(&p, " "); if (strcmp(a, "DISK")) continue; a = strsep(&p, " "); if (strcmp(a, name)) continue; break; } q = strchr(p, '\n'); if (q != NULL) *q++ = '\0'; d = (struct disk *)calloc(sizeof *d, 1); if(d == NULL) return NULL; d->name = strdup(name); a = strsep(&p, " "); /* length in bytes */ len = strtoimax(a, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } a = strsep(&p, " "); /* sectorsize */ s = strtoul(a, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } if (s == 0) return (NULL); d->sector_size = s; len /= s; /* media size in number of sectors. */ if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) DPRINT(("Failed to add 'whole' chunk")); for (;;) { a = strsep(&p, " "); if (a == NULL) break; b = strsep(&p, " "); - o = strtoul(b, &r, 0); + o = strtoimax(b, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } if (!strcmp(a, "hd")) d->bios_hd = o; else if (!strcmp(a, "sc")) d->bios_sect = o; else printf("HUH ? <%s> <%s>\n", a, b); } /* * Calculate the number of cylinders this disk must have. If we have * an obvious insanity, we set the number of cyclinders to zero. */ o = d->bios_hd * d->bios_sect; d->bios_cyl = (o != 0) ? len / o : 0; p = q; lo[0] = 0; for (; p != NULL && *p; p = q) { q = strchr(p, '\n'); if (q != NULL) *q++ = '\0'; a = strsep(&p, " "); /* Index */ if (!strcmp(a, "0")) break; l = strtoimax(a, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } t = strsep(&p, " "); /* Type {SUN, BSD, MBR, PC98, GPT} */ n = strsep(&p, " "); /* name */ a = strsep(&p, " "); /* len */ len = strtoimax(a, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } a = strsep(&p, " "); /* secsize */ s = strtoimax(a, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } for (;;) { a = strsep(&p, " "); if (a == NULL) break; /* XXX: Slice name may include a space. */ if (!strcmp(a, "sn")) { sn = p; break; } b = strsep(&p, " "); o = strtoimax(b, &r, 0); if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); } if (!strcmp(a, "o")) off = o; else if (!strcmp(a, "i")) i = o; else if (!strcmp(a, "ty")) ty = o; else if (!strcmp(a, "sc")) sc = o; else if (!strcmp(a, "hd")) hd = o; else if (!strcmp(a, "alt")) alt = o; } /* PLATFORM POLICY BEGIN ----------------------------------- */ if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) continue; if (platform == p_sparc64 && !strcmp(t, "SUN") && d->chunks->part->part == NULL) { d->bios_hd = hd; d->bios_sect = sc; o = d->chunks->size / (hd * sc); o *= (hd * sc); o -= alt * hd * sc; if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) DPRINT(("Failed to add 'freebsd' chunk")); } if (platform == p_alpha && !strcmp(t, "BSD") && d->chunks->part->part == NULL) { if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, 0, 0, "-")) DPRINT(("Failed to add 'freebsd' chunk")); } if (!strcmp(t, "BSD") && i == RAW_PART) continue; /* PLATFORM POLICY END ------------------------------------- */ off /= s; len /= s; off += lo[l - 1]; lo[l] = off; if (!strcmp(t, "SUN")) i = Add_Chunk(d, off, len, n, part, 0, 0, 0); else if (!strncmp(t, "MBR", 3)) { switch (ty) { case 0xa5: i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0); break; case 0x01: case 0x04: case 0x06: case 0x0b: case 0x0c: case 0x0e: i = Add_Chunk(d, off, len, n, fat, ty, 0, 0); break; case 0xef: /* EFI */ i = Add_Chunk(d, off, len, n, efi, ty, 0, 0); break; default: i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0); break; } } else if (!strcmp(t, "BSD")) i = Add_Chunk(d, off, len, n, part, ty, 0, 0); else if (!strcmp(t, "PC98")) { switch (ty & 0x7f) { case 0x14: i = Add_Chunk(d, off, len, n, freebsd, ty, 0, sn); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: i = Add_Chunk(d, off, len, n, fat, ty, 0, sn); break; default: i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn); break; } } else if (!strcmp(t, "GPT")) i = Add_Chunk(d, off, len, n, ty, 0, 0, 0); else if (!strcmp(t, "BDE")) ; /* nothing */ else if (!strcmp(t, "CCD")) ; /* nothing */ else { printf("BARF %d\n", __LINE__); exit(0); } } /* PLATFORM POLICY BEGIN ------------------------------------- */ /* We have a chance to do things on a blank disk here */ if (platform == p_sparc64 && d->chunks->part->part == NULL) { hd = d->bios_hd; sc = d->bios_sect; o = d->chunks->size / (hd * sc); o *= (hd * sc); o -= 2 * hd * sc; if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) DPRINT(("Failed to add 'freebsd' chunk")); } /* PLATFORM POLICY END --------------------------------------- */ return (d); i = 0; } diff --git a/lib/libdisk/rules.c b/lib/libdisk/rules.c index b725b3225a04..6c7f315a38c0 100644 --- a/lib/libdisk/rules.c +++ b/lib/libdisk/rules.c @@ -1,295 +1,296 @@ /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ #include __FBSDID("$FreeBSD$"); -#include -#include -#include -#include #include +#include #include #ifdef PC98 #include #else #include #endif +#include +#include +#include +#include #include "libdisk.h" int -Track_Aligned(const struct disk *d, u_long offset) +Track_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect) return 1; if (offset % d->bios_sect) return 0; #endif /* __ia64__ */ return 1; } -u_long -Prev_Track_Aligned(const struct disk *d, u_long offset) +daddr_t +Prev_Track_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect) return offset; return (offset / d->bios_sect) * d->bios_sect; #else return 1; #endif } -u_long -Next_Track_Aligned(const struct disk *d, u_long offset) +daddr_t +Next_Track_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect) return offset; return Prev_Track_Aligned(d, offset + d->bios_sect-1); #else return 1; #endif } static int -Cyl_Aligned(const struct disk *d, u_long offset) +Cyl_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect || !d->bios_hd) return 1; if (offset % (d->bios_sect * d->bios_hd)) return 0; #endif return 1; } -u_long -Prev_Cyl_Aligned(const struct disk *d, u_long offset) +daddr_t +Prev_Cyl_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect || !d->bios_hd) return offset; return (offset / (d->bios_sect * d->bios_hd)) * d->bios_sect * d->bios_hd; #else return 1; #endif } -u_long -Next_Cyl_Aligned(const struct disk *d, u_long offset) +daddr_t +Next_Cyl_Aligned(const struct disk *d, daddr_t offset) { #ifndef __ia64__ if (!d->bios_sect || !d->bios_hd) return offset; return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd) - 1); #else return 1; #endif } /* * Rule#0: * Chunks of type 'whole' can have max NDOSPART children. * Only one of them can have the "active" flag */ static void Rule_000(const struct disk *d, const struct chunk *c, char *msg) { #ifdef PC98 int i = 0; #else int i = 0, j = 0; #endif struct chunk *c1; if (c->type != whole) return; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) continue; #ifndef PC98 if (c1->flags & CHUNK_ACTIVE) j++; #endif i++; } if (i > NDOSPART) sprintf(msg + strlen(msg), "%d is too many children of the 'whole' chunk." " Max is %d\n", i, NDOSPART); #ifndef PC98 if (j > 1) sprintf(msg + strlen(msg), "Too many active children of 'whole'"); #endif } /* * Rule#1: * All children of 'whole' and 'extended' must be track-aligned. * Exception: the end can be unaligned if it matches the end of 'whole' */ static void Rule_001(const struct disk *d, const struct chunk *c, char *msg) { struct chunk *c1; if (c->type != whole && c->type != extended) return; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type == unused) continue; c1->flags |= CHUNK_ALIGN; #ifdef PC98 if (!Cyl_Aligned(d, c1->offset)) #else if (!Track_Aligned(d, c1->offset)) #endif sprintf(msg + strlen(msg), #ifdef PC98 - "chunk '%s' [%ld..%ld] does not start" + "chunk '%s' [%jd..%jd] does not start" " on a cylinder boundary\n", #else - "chunk '%s' [%ld..%ld] does not start" + "chunk '%s' [%jd..%jd] does not start" " on a track boundary\n", #endif - c1->name, c1->offset, c1->end); + c1->name, (intmax_t)c1->offset, (intmax_t)c1->end); if ((c->type == whole || c->end == c1->end) || Cyl_Aligned(d, c1->end + 1)) ; else sprintf(msg + strlen(msg), - "chunk '%s' [%ld..%ld] does not end" + "chunk '%s' [%jd..%jd] does not end" " on a cylinder boundary\n", - c1->name, c1->offset, c1->end); + c1->name, (intmax_t)c1->offset, (intmax_t)c1->end); } } /* * Rule#2: * Max one 'fat' as child of 'whole' */ static void Rule_002(const struct disk *d, const struct chunk *c, char *msg) { int i; struct chunk *c1; if (c->type != whole) return; for (i = 0, c1 = c->part; c1; c1 = c1->next) { if (c1->type != fat) continue; i++; } if (i > 1) { sprintf(msg + strlen(msg), "Max one 'fat' allowed as child of 'whole'\n"); } } /* * Rule#3: * Max one extended as child of 'whole' */ static void Rule_003(const struct disk *d, const struct chunk *c, char *msg) { int i; struct chunk *c1; if (c->type != whole) return; for (i = 0, c1 = c->part; c1; c1 = c1->next) { if (c1->type != extended) continue; i++; } if (i > 1) { sprintf(msg + strlen(msg), "Max one 'extended' allowed as child of 'whole'\n"); } } /* * Rule#4: * Max seven 'part' as children of 'freebsd' * Max one CHUNK_IS_ROOT child per 'freebsd' */ static void Rule_004(const struct disk *d, const struct chunk *c, char *msg) { int i = 0, k = 0; struct chunk *c1; if (c->type != freebsd) return; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != part) continue; if (c1->flags & CHUNK_IS_ROOT) k++; i++; } if (i > 7) { sprintf(msg + strlen(msg), "Max seven partitions per freebsd slice\n"); } if (k > 1) { sprintf(msg + strlen(msg), "Max one root partition child per freebsd slice\n"); } } static void Check_Chunk(const struct disk *d, const struct chunk *c, char *msg) { switch (platform) { case p_i386: case p_amd64: Rule_000(d, c, msg); Rule_001(d, c, msg); Rule_002(d, c, msg); Rule_003(d, c, msg); Rule_004(d, c, msg); if (c->part) Check_Chunk(d, c->part, msg); if (c->next) Check_Chunk(d, c->next, msg); break; case p_pc98: Rule_000(d, c, msg); Rule_001(d, c, msg); Rule_004(d, c, msg); if (c->part) Check_Chunk(d, c->part, msg); if (c->next) Check_Chunk(d, c->next, msg); break; default: break; } } char * CheckRules(const struct disk *d) { char msg[BUFSIZ]; *msg = '\0'; Check_Chunk(d, d->chunks, msg); if (*msg) return strdup(msg); return 0; } diff --git a/usr.sbin/sade/disks.c b/usr.sbin/sade/disks.c index 4fba2c7df83b..535fb058373c 100644 --- a/usr.sbin/sade/disks.c +++ b/usr.sbin/sade/disks.c @@ -1,991 +1,996 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include +#include #include #include #ifdef WITH_SLICES enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; #ifdef PC98 #define SUBTYPE_FREEBSD 50324 #define SUBTYPE_FAT 37218 #else #define SUBTYPE_FREEBSD 165 #define SUBTYPE_FAT 6 #endif #define SUBTYPE_EFI 239 #ifdef PC98 #define OTHER_SLICE_VALUES \ "Other popular values are 37218 for a\n" \ "DOS FAT partition.\n\n" #else #define OTHER_SLICE_VALUES \ "Other popular values are 6 for a\n" \ "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ "130 for a Linux swap partition.\n\n" #endif #define NON_FREEBSD_NOTE \ "Note: If you choose a non-FreeBSD partition type, it will not\n" \ "be formatted or otherwise prepared, it will simply reserve space\n" \ "for you to use another tool, such as DOS format, to later format\n" \ "and actually use the partition." /* Where we start displaying chunk information on the screen */ #define CHUNK_START_ROW 5 /* Where we keep track of MBR chunks */ static struct chunk *chunk_info[16]; static int current_chunk; static void diskPartitionNonInteractive(Device *dev); static u_char * bootalloc(char *name, size_t *size); static void record_chunks(Disk *d) { struct chunk *c1 = NULL; int i = 0; - int last_free = 0; + daddr_t last_free = 0; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == unused && c1->size > last_free) { last_free = c1->size; current_chunk = i; } chunk_info[i++] = c1; } chunk_info[i] = NULL; if (current_chunk >= i) current_chunk = i - 1; } -static int Total; +static daddr_t Total; static void print_chunks(Disk *d, int u) { int row; int i; - int sz; + daddr_t sz; char *szstr; szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST"))); - for (i = Total = 0; chunk_info[i]; i++) + Total = 0; + for (i = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; #ifdef PC98 if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { #else if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { #endif dialog_clear_norefresh(); msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" "a more likely geometry. If this geometry is incorrect or you\n" "are unsure as to whether or not it's correct, please consult\n" "the Hardware Guide in the Documentation submenu or use the\n" "(G)eometry command to change it now.\n\n" "Remember: you need to enter whatever your BIOS thinks the\n" "geometry is! For IDE, it's what you were told in the BIOS\n" "setup. For SCSI, it's the translation mode your controller is\n" "using. Do NOT use a ``physical geometry''.", d->bios_cyl, d->bios_hd, d->bios_sect, d->name); Sanitize_Bios_Geom(d); } attrset(A_NORMAL); mvaddstr(0, 0, "Disk name:\t"); clrtobot(); attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); mvprintw(1, 0, - "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", + "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %jd sectors (%jdMB)", d->bios_cyl, d->bios_hd, d->bios_sect, - d->bios_cyl * d->bios_hd * d->bios_sect, - d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect, + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", "Offset", "Size", szstr, "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { switch(u) { default: /* fall thru */ case UNIT_BLOCKS: sz = chunk_info[i]->size; break; case UNIT_KILO: sz = chunk_info[i]->size / (1024/512); break; case UNIT_MEG: sz = chunk_info[i]->size / (1024/512) / 1024; break; case UNIT_GIG: sz = chunk_info[i]->size / (1024/512) / 1024 / 1024; break; } if (i == current_chunk) attrset(ATTR_SELECTED); - mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", - chunk_info[i]->offset, sz, - chunk_info[i]->end, chunk_info[i]->name, + mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s", + (intmax_t)chunk_info[i]->offset, (intmax_t)sz, + (intmax_t)chunk_info[i]->end, chunk_info[i]->name, chunk_info[i]->type, slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); if (i == current_chunk) attrset(A_NORMAL); } } static void print_command_summary() { mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); if (!RunningAsInit) mvprintw(18, 47, "W = Write Changes"); mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } #ifdef PC98 static void getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, u_char **bootmenu, size_t *bootmenu_size) { static u_char *boot0; static size_t boot0_size; static u_char *boot05; static size_t boot05_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of IPL the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuIPLType.title = str; i = dmenuOpenSimple(&MenuIPLType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else BootMgr = 1; } if (cp || i) { switch (BootMgr) { case 0: if (!boot0) boot0 = bootalloc("boot0", &boot0_size); *bootipl = boot0; *bootipl_size = boot0_size; if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); *bootmenu = boot05; *bootmenu_size = boot05_size; return; case 1: default: break; } } *bootipl = NULL; *bootipl_size = 0; *bootmenu = NULL; *bootmenu_size = 0; } #else static void getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) { #if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ static u_char *mbr, *boot0; static size_t mbr_size, boot0_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else if (!strcmp(cp, "standard")) BootMgr = 1; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: if (!boot0) boot0 = bootalloc("boot0", &boot0_size); *bootCode = boot0; *bootCodeSize = boot0_size; return; case 1: if (!mbr) mbr = bootalloc("mbr", &mbr_size); *bootCode = mbr; *bootCodeSize = mbr_size; return; case 2: default: break; } } #endif *bootCode = NULL; *bootCodeSize = 0; } #endif #endif /* WITH_SLICES */ int diskGetSelectCount(Device ***devs) { int i, cnt, enabled; char *cp; Device **dp; cp = variable_get(VAR_DISK); dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(dp); if (!cnt) return -1; for (i = 0, enabled = 0; i < cnt; i++) { if (dp[i]->enabled) ++enabled; } return enabled; } #ifdef WITH_SLICES void diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif WINDOW *w = savescr(); Disk *d = (Disk *)dev->private; int size_unit; size_unit = UNIT_BLOCKS; chunking = TRUE; keypad(stdscr, TRUE); /* Flush both the dialog and curses library views of the screen since we don't always know who called us */ dialog_clear_norefresh(), clear(); current_chunk = 0; /* Set up the chunk array */ record_chunks(d); while (chunking) { char *val, geometry[80]; /* Now print our overall state */ if (d) print_chunks(d, size_unit); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } /* Get command character */ key = getch(); switch (toupper(key)) { case '\014': /* ^L (redraw) */ clear(); msg = NULL; break; case '\020': /* ^P */ case KEY_UP: case '-': if (current_chunk != 0) --current_chunk; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_HOME: current_chunk = 0; break; case KEY_END: while (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_F(1): case '?': systemDisplayHelp("slice"); clear(); break; case 'A': case 'F': /* Undocumented magic Dangerously Dedicated mode */ #if !defined(__i386__) && !defined(__amd64__) && !defined(__ia64__) rv = 1; #else /* The rest is only relevant on x86 */ cp = variable_get(VAR_DEDICATE_DISK); if (cp && !strcasecmp(cp, "always")) rv = 1; else if (toupper(key) == 'A') rv = 0; else { rv = msgYesNo("Do you want to do this with a true partition entry\n" "so as to remain cooperative with any future possible\n" "operating systems on the drive(s)?\n" "(See also the section about ``dangerously dedicated''\n" "disks in the FreeBSD FAQ.)"); if (rv == -1) rv = 0; } #endif All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); clear(); break; case 'C': if (chunk_info[current_chunk]->type != unused) msg = "Slice in use, delete it first or move to an unused one."; else { char *val, tmp[20], name[16], *cp; - int size, subtype; + daddr_t size; + int subtype; chunk_e partitiontype; #ifdef PC98 snprintf(name, sizeof (name), "%s", "FreeBSD"); val = msgGetInput(name, "Please specify the name for new FreeBSD slice."); if (val) strncpy(name, val, sizeof (name)); #else name[0] = '\0'; #endif - snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); + snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size); val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" "or append a trailing `M' for megabytes (e.g. 20M)."); - if (val && (size = strtol(val, &cp, 0)) > 0) { + if (val && (size = strtoimax(val, &cp, 0)) > 0) { if (*cp && toupper(*cp) == 'M') size *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') size *= ONE_GIG; sprintf(tmp, "%d", SUBTYPE_FREEBSD); val = msgGetInput(tmp, "Enter type of partition to create:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type %u). " OTHER_SLICE_VALUES NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else if (subtype == SUBTYPE_EFI) partitiontype = efi; else #ifdef PC98 partitiontype = pc98; #else partitiontype = mbr; #endif Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } } clear(); } break; case KEY_DC: case 'D': if (chunk_info[current_chunk]->type == unused) msg = "Slice is already unused!"; else { Delete_Chunk(d, chunk_info[current_chunk]); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } break; case 'T': if (chunk_info[current_chunk]->type == unused) msg = "Slice is currently unused (use create instead)"; else { char *val, tmp[20]; int subtype; chunk_e partitiontype; sprintf(tmp, "%d", chunk_info[current_chunk]->subtype); val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will use the current type. To choose a native\n" "FreeBSD slice enter %u. " OTHER_SLICE_VALUES NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else if (subtype == SUBTYPE_EFI) partitiontype = efi; else #ifdef PC98 partitiontype = pc98; #else partitiontype = mbr; #endif chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } } break; case 'G': snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" "Don't forget to use the two slash (/) separator characters!\n" "It's not possible to parse the field without them."); if (val) { long nc, nh, ns; nc = strtol(val, &val, 0); nh = strtol(val + 1, &val, 0); ns = strtol(val + 1, 0, 0); Set_Bios_Geom(d, nc, nh, ns); } clear(); break; case 'S': /* Set Bootable */ chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; break; case 'U': if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written this information out - you\n" "can't undo it."); } else if (!msgNoYes("Are you SURE you want to Undo everything?")) { char cp[BUFSIZ]; sstrncpy(cp, d->name, sizeof cp); Free_Disk(dev->private); d = Open_Disk(cp); if (!d) msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); dev->private = d; variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); if (d) record_chunks(d); } clear(); break; case 'W': if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions. If you're adding a disk, you should NOT write\n" "from this screen, you should do it from the label editor.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_PARTITIONED, "yes", 0); #ifdef PC98 /* * Don't trash the IPL if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested a FreeBSD Boot Manager -- both would be fatal in * this case. */ /* * Don't offer to update the IPL on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); else { bootipl = NULL; bootipl_size = 0; bootmenu = NULL; bootmenu_size = 0; } Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested booteasy or a "standard" MBR -- both would be * fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &mbrContents, &mbrSize); else { mbrContents = NULL; mbrSize = 0; } Set_Boot_Mgr(d, mbrContents, mbrSize); #endif if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) msgConfirm("Disk partition write returned an error status!"); else msgConfirm("Wrote FDISK partition information out successfully."); } clear(); break; #ifndef __ia64__ case '|': if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } else msg = "Wise choice!"; clear(); break; #endif case '\033': /* ESC */ case 'Q': chunking = FALSE; #ifdef PC98 /* * Don't trash the IPL if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * a FreeBSD Boot Manager -- both would be fatal in this case. */ /* * Don't offer to update the IPL on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { if (variable_cmp(DISK_PARTITIONED, "written")) { getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); } } #else /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * booteasy or a "standard" MBR -- both would be fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { if (variable_cmp(DISK_PARTITIONED, "written")) { getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); } } #endif break; case 'Z': size_unit = (size_unit + 1) % UNIT_SIZE; break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; use_helpline("Press F1 to read more about disk slices."); use_helpfile(systemHelpFile("partition", buf)); if (!variable_get(VAR_NO_WARN)) dialog_mesgbox("Disk slicing warning:", p, -1, -1); free(p); } restorescr(w); } #endif /* WITH_SLICES */ static u_char * bootalloc(char *name, size_t *size) { char buf[FILENAME_MAX]; struct stat sb; snprintf(buf, sizeof buf, "/boot/%s", name); if (stat(buf, &sb) != -1) { int fd; fd = open(buf, O_RDONLY); if (fd != -1) { u_char *cp; cp = malloc(sb.st_size); if (read(fd, cp, sb.st_size) != sb.st_size) { free(cp); close(fd); msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); return NULL; } close(fd); if (size != NULL) *size = sb.st_size; return cp; } msgDebug("bootalloc: couldn't open %s\n", buf); } else msgDebug("bootalloc: can't stat %s\n", buf); return NULL; } #ifdef WITH_SLICES static int partitionHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskPartition(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int partitionCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskPartitionEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt, devcnt; cnt = diskGetSelectCount(&devs); devcnt = deviceCount(devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ for (i = 0; i < devcnt; i++) { if (devs[i]->enabled) { if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) diskPartitionNonInteractive(devs[i]); else diskPartition(devs[i]); } } } else { /* No disks are selected, fall-back case now */ if (devcnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) diskPartitionNonInteractive(devs[0]); else diskPartition(devs[0]); return DITEM_SUCCESS; } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); return DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } return i; } } return DITEM_SUCCESS; } #endif /* WITH_SLICES */ int diskPartitionWrite(dialogMenuItem *self) { Device **devs; int i; if (!variable_cmp(DISK_PARTITIONED, "written")) return DITEM_SUCCESS; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find any disks to write to??"); return DITEM_FAILURE; } if (isDebug()) msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); for (i = 0; devs[i]; i++) { Disk *d = (Disk *)devs[i]->private; static u_char *boot1; #if defined(__i386__) || defined(__ia64__) || defined(__amd64__) static u_char *boot2; #endif if (!devs[i]->enabled) continue; #if defined(__i386__) || defined(__amd64__) if (!boot1) boot1 = bootalloc("boot1", NULL); if (!boot2) boot2 = bootalloc("boot2", NULL); Set_Boot_Blocks(d, boot1, boot2); #elif !defined(__ia64__) if (!boot1) boot1 = bootalloc("boot1", NULL); Set_Boot_Blocks(d, boot1, NULL); #endif msgNotify("Writing partition information to drive %s", d->name); if (!Fake && Write_Disk(d)) { msgConfirm("ERROR: Unable to write data to disk %s!", d->name); return DITEM_FAILURE; } } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written", 0); return DITEM_SUCCESS | DITEM_RESTORE; } #ifdef WITH_SLICES /* Partition a disk based wholly on which variables are set */ static void diskPartitionNonInteractive(Device *dev) { char *cp; - int i, sz, all_disk = 0; + int i, all_disk = 0; + daddr_t sz; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif Disk *d = (Disk *)dev->private; record_chunks(d); cp = variable_get(VAR_GEOMETRY); if (cp) { msgDebug("Setting geometry from script to: %s\n", cp); d->bios_cyl = strtol(cp, &cp, 0); d->bios_hd = strtol(cp + 1, &cp, 0); d->bios_sect = strtol(cp + 1, 0, 0); } cp = variable_get(VAR_PARTITION); if (cp) { if (!strcmp(cp, "free")) { /* Do free disk space case */ for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least 10MB in size, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find any free space on this disk!"); return; } } else if (!strcmp(cp, "all")) { /* Do all disk space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, FALSE); } else if (!strcmp(cp, "exclusive")) { /* Do really-all-the-disk-space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, all_disk = TRUE); } - else if ((sz = strtol(cp, &cp, 0))) { + else if ((sz = strtoimax(cp, &cp, 0))) { /* Look for sz bytes free */ if (*cp && toupper(*cp) == 'M') sz *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') sz *= ONE_GIG; for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least sz MB, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { - msgConfirm("Unable to find %d free blocks on this disk!", sz); + msgConfirm("Unable to find %jd free blocks on this disk!", + (intmax_t)sz); return; } } else if (!strcmp(cp, "existing")) { /* Do existing FreeBSD case */ for (i = 0; chunk_info[i]; i++) { if (chunk_info[i]->type == freebsd) break; } if (!chunk_info[i]) { msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } variable_set2(DISK_PARTITIONED, "yes", 0); } } #endif /* WITH_SLICES */ diff --git a/usr.sbin/sade/label.c b/usr.sbin/sade/label.c index 5b4a51c5a2ca..e75da48dc86b 100644 --- a/usr.sbin/sade/label.c +++ b/usr.sbin/sade/label.c @@ -1,1671 +1,1676 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include +#include #include #include #include #define AUTO_HOME 0 /* do not create /home automatically */ /* * Everything to do with editing the contents of disk labels. */ /* A nice message we use a lot in the disklabel editor */ #define MSG_NOT_APPLICABLE "That option is not applicable here" /* Where to start printing the freebsd slices */ #define CHUNK_SLICE_START_ROW 2 #define CHUNK_PART_START_ROW 11 /* The smallest filesystem we're willing to create */ #define FS_MIN_SIZE ONE_MEG /* * Minimum partition sizes */ #if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) || defined(__amd64__) #define ROOT_MIN_SIZE 128 #else #define ROOT_MIN_SIZE 118 #endif #define SWAP_MIN_SIZE 32 #define USR_MIN_SIZE 80 #define VAR_MIN_SIZE 20 #define TMP_MIN_SIZE 20 #define HOME_MIN_SIZE 20 /* * Swap size limit for auto-partitioning (4G). */ #define SWAP_AUTO_LIMIT_SIZE 4096 /* * Default partition sizes. If we do not have sufficient disk space * for this configuration we scale things relative to the NOM vs DEFAULT * sizes. If the disk is larger then /home will get any remaining space. */ #define ROOT_DEFAULT_SIZE 256 #define USR_DEFAULT_SIZE 3072 #define VAR_DEFAULT_SIZE 256 #define TMP_DEFAULT_SIZE 256 #define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE /* * Nominal partition sizes. These are used to scale the default sizes down * when we have insufficient disk space. If this isn't sufficient we scale * down using the MIN sizes instead. */ #define ROOT_NOMINAL_SIZE 192 #define USR_NOMINAL_SIZE 512 #define VAR_NOMINAL_SIZE 64 #define TMP_NOMINAL_SIZE 64 #define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE /* The bottom-most row we're allowed to scribble on */ #define CHUNK_ROW_MAX 16 /* All the chunks currently displayed on the screen */ static struct { struct chunk *c; PartType type; } label_chunk_info[MAX_CHUNKS + 1]; static int here; /*** with this value we try to track the most recently added label ***/ static int label_focus = 0, pslice_focus = 0; static int diskLabel(Device *dev); static int diskLabelNonInteractive(Device *dev); static char *try_auto_label(Device **devs, Device *dev, int perc, int *req); static int labelHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskLabel(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int labelCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskLabelEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt; i = 0; cnt = diskGetSelectCount(&devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) i = diskLabelNonInteractive(NULL); else i = diskLabel(NULL); } else { /* No disks are selected, fall-back case now */ cnt = deviceCount(devs); if (cnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) i = diskLabelNonInteractive(devs[0]); else i = diskLabel(devs[0]); } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); i = DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } } } if (DITEM_STATUS(i) != DITEM_FAILURE) { if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } return i; } int diskLabelCommit(dialogMenuItem *self) { char *cp; int i; /* Already done? */ if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) i = DITEM_SUCCESS; else if (!cp) { msgConfirm("You must assign disk labels before this option can be used."); i = DITEM_FAILURE; } /* The routine will guard against redundant writes, just as this one does */ else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else { msgInfo("All filesystem information written successfully."); variable_set2(DISK_LABELLED, "written", 0); i = DITEM_SUCCESS; } return i; } /* See if we're already using a desired partition name */ static Boolean check_conflict(char *name) { int i; for (i = 0; label_chunk_info[i].c; i++) if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) return TRUE; return FALSE; } /* How much space is in this FreeBSD slice? */ -static int +static daddr_t space_free(struct chunk *c) { struct chunk *c1; - int sz = c->size; + daddr_t sz = c->size; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) sz -= c1->size; } if (sz < 0) msgFatal("Partitions are larger than actual chunk??"); return sz; } /* Snapshot the current situation into the displayed chunks structure */ static void record_label_chunks(Device **devs, Device *dev) { int i, j, p; struct chunk *c1, *c2; Disk *d; j = p = 0; /* First buzz through and pick up the FreeBSD slices */ for (i = 0; devs[i]; i++) { if ((dev && devs[i] != dev) || !devs[i]->enabled) continue; d = (Disk *)devs[i]->private; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); #ifdef __ia64__ label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = d->chunks; j++; #endif /* Put the slice entries first */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = c1; ++j; } } } /* Now run through again and get the FreeBSD partition entries */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; d = (Disk *)devs[i]->private; /* Then buzz through and pick up the partitions */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part) { if (c2->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c2; ++j; } } } else if (c1->type == fat) { label_chunk_info[j].type = PART_FAT; label_chunk_info[j].c = c1; ++j; } #ifdef __ia64__ else if (c1->type == efi) { label_chunk_info[j].type = PART_EFI; label_chunk_info[j].c = c1; ++j; } else if (c1->type == part) { if (c1->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c1; ++j; } #endif } } label_chunk_info[j].c = NULL; if (here >= j) { here = j ? j - 1 : 0; } } /* A new partition entry */ static PartInfo * new_part(char *mpoint, Boolean newfs) { PartInfo *pi; if (!mpoint) mpoint = "/change_me"; pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); pi->do_newfs = newfs; pi->newfs_type = NEWFS_UFS; strcpy(pi->newfs_data.newfs_ufs.user_options, ""); pi->newfs_data.newfs_ufs.acls = FALSE; pi->newfs_data.newfs_ufs.multilabel = FALSE; pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/"); #ifdef PC98 pi->newfs_data.newfs_ufs.ufs1 = TRUE; #else pi->newfs_data.newfs_ufs.ufs1 = FALSE; #endif return pi; } #if defined(__ia64__) static PartInfo * new_efi_part(char *mpoint, Boolean newfs) { PartInfo *pi; if (!mpoint) mpoint = "/efi"; pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); pi->do_newfs = newfs; pi->newfs_type = NEWFS_MSDOS; return pi; } #endif /* Get the mountpoint for a partition and save it away */ static PartInfo * get_mountpoint(struct chunk *old) { char *val; PartInfo *tmp; Boolean newfs; if (old && old->private_data) tmp = old->private_data; else tmp = NULL; val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); if (!val || !*val) { if (!old) return NULL; else { free(old->private_data); old->private_data = NULL; } return NULL; } /* Is it just the same value? */ if (tmp && !strcmp(tmp->mountpoint, val)) return NULL; /* Did we use it already? */ if (check_conflict(val)) { msgConfirm("You already have a mount point for %s assigned!", val); return NULL; } /* Is it bogus? */ if (*val != '/') { msgConfirm("Mount point must start with a / character"); return NULL; } /* Is it going to be mounted on root? */ if (!strcmp(val, "/")) { if (old) old->flags |= CHUNK_IS_ROOT; } else if (old) old->flags &= ~CHUNK_IS_ROOT; newfs = TRUE; if (tmp) { newfs = tmp->do_newfs; safe_free(tmp); } val = string_skipwhite(string_prune(val)); tmp = new_part(val, newfs); if (old) { old->private_data = tmp; old->private_free = safe_free; } return tmp; } /* Get the type of the new partiton */ static PartType get_partition_type(void) { char selection[20]; int i; static unsigned char *fs_types[] = { #ifdef __ia64__ "EFI", "An EFI system partition", #endif "FS", "A file system", "Swap", "A swap partition.", }; WINDOW *w = savescr(); i = dialog_menu("Please choose a partition type", "If you want to use this partition for swap space, select Swap.\n" "If you want to put a filesystem on it, choose FS.", -1, -1, #ifdef __ia64__ 3, 3, #else 2, 2, #endif fs_types, selection, NULL, NULL); restorescr(w); if (!i) { #ifdef __ia64__ if (!strcmp(selection, "EFI")) return PART_EFI; #endif if (!strcmp(selection, "FS")) return PART_FILESYSTEM; else if (!strcmp(selection, "Swap")) return PART_SWAP; } return PART_NONE; } /* If the user wants a special newfs command for this, set it */ static void getNewfsCmd(PartInfo *p) { char buffer[NEWFS_CMD_ARGS_MAX]; char *val; switch (p->newfs_type) { case NEWFS_UFS: snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s", NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ? "-U" : "", p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", p->newfs_data.newfs_ufs.user_options); break; case NEWFS_MSDOS: snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD); break; case NEWFS_CUSTOM: strcpy(buffer, p->newfs_data.newfs_custom.command); break; } val = msgGetInput(buffer, "Please enter the newfs command and options you'd like to use in\n" "creating this file system."); if (val != NULL) { p->newfs_type = NEWFS_CUSTOM; strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX); } } static void getNewfsOptionalArguments(PartInfo *p) { char buffer[NEWFS_CMD_ARGS_MAX]; char *val; /* Must be UFS, per argument checking in I/O routines. */ strlcpy(buffer, p->newfs_data.newfs_ufs.user_options, NEWFS_CMD_ARGS_MAX); val = msgGetInput(buffer, "Please enter any additional UFS newfs options you'd like to\n" "use in creating this file system."); if (val != NULL) strlcpy(p->newfs_data.newfs_ufs.user_options, val, NEWFS_CMD_ARGS_MAX); } #define MAX_MOUNT_NAME 9 #define PART_PART_COL 0 #define PART_MOUNT_COL 10 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 8) #define PART_OFF 38 #define TOTAL_AVAIL_LINES (10) #define PSLICE_SHOWABLE (4) /* stick this all up on the screen */ static void print_label_chunks(void) { - int i, j, spaces, srow, prow, pcol; - int sz; + int i, j, srow, prow, pcol; + daddr_t sz; char clrmsg[80]; int ChunkPartStartRow; WINDOW *ChunkWin; /********************************************************/ /*** These values are for controling screen resources ***/ /*** Each label line holds up to 2 labels, so beware! ***/ /*** strategy will be to try to always make sure the ***/ /*** highlighted label is in the active display area. ***/ /********************************************************/ int pslice_max, label_max; int pslice_count, label_count, label_focus_found, pslice_focus_found; attrset(A_REVERSE); mvaddstr(0, 25, "FreeBSD Disklabel Editor"); attrset(A_NORMAL); /*** Count the number of parition slices ***/ pslice_count = 0; for (i = 0; label_chunk_info[i].c ; i++) { if (label_chunk_info[i].type == PART_SLICE) ++pslice_count; } pslice_max = pslice_count; /*** 4 line max for partition slices ***/ if (pslice_max > PSLICE_SHOWABLE) { pslice_max = PSLICE_SHOWABLE; } ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; /*** View partition slices modulo pslice_max ***/ label_max = TOTAL_AVAIL_LINES - pslice_max; for (i = 0; i < 2; i++) { mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); } srow = CHUNK_SLICE_START_ROW; prow = 0; pcol = 0; /*** these variables indicate that the focused item is shown currently ***/ label_focus_found = 0; pslice_focus_found = 0; label_count = 0; pslice_count = 0; mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); wclear(ChunkWin); /*** wrefresh(ChunkWin); ***/ for (i = 0; label_chunk_info[i].c; i++) { /* Is it a slice entry displayed at the top? */ if (label_chunk_info[i].type == PART_SLICE) { /*** This causes the new pslice to replace the previous display ***/ /*** focus must remain on the most recently active pslice ***/ if (pslice_count == pslice_max) { if (pslice_focus_found) { /*** This is where we can mark the more following ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); attrset(A_NORMAL); continue; } else { /*** this is where we set the more previous ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); attrset(A_NORMAL); pslice_count = 0; srow = CHUNK_SLICE_START_ROW; } } sz = space_free(label_chunk_info[i].c); if (i == here) attrset(ATTR_SELECTED); if (i == pslice_focus) pslice_focus_found = -1; if (label_chunk_info[i].c->type == whole) { if (sz >= 100 * ONE_GIG) mvprintw(srow++, 0, - "Disk: %s\t\tFree: %d blocks (%dGB)", - label_chunk_info[i].c->disk->name, sz, (sz / ONE_GIG)); + "Disk: %s\t\tFree: %jd blocks (%jdGB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_GIG)); else mvprintw(srow++, 0, - "Disk: %s\t\tFree: %d blocks (%dMB)", - label_chunk_info[i].c->disk->name, sz, (sz / ONE_MEG)); + "Disk: %s\t\tFree: %jd blocks (%jdMB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_MEG)); } else { if (sz >= 100 * ONE_GIG) mvprintw(srow++, 0, - "Disk: %s\tPartition name: %s\tFree: %d blocks (%dGB)", + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, - sz, (sz / ONE_GIG)); + (intmax_t)sz, (intmax_t)(sz / ONE_GIG)); else mvprintw(srow++, 0, - "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, - sz, (sz / ONE_MEG)); + (intmax_t)sz, (intmax_t)(sz / ONE_MEG)); } attrset(A_NORMAL); clrtoeol(); move(0, 0); /*** refresh(); ***/ ++pslice_count; } /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ else { char onestr[PART_OFF], num[10], *mountpoint, newfs[12]; /* * We copy this into a blank-padded string so that it looks like * a solid bar in reverse-video */ memset(onestr, ' ', PART_OFF - 1); onestr[PART_OFF - 1] = '\0'; /*** Track how many labels have been displayed ***/ if (label_count == ((label_max - 1 ) * 2)) { if (label_focus_found) { continue; } else { label_count = 0; prow = 0; pcol = 0; } } /* Go for two columns if we've written one full columns worth */ /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ if (label_count == label_max - 1) { pcol = PART_OFF; prow = 0; } memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); /* If it's a filesystem, display the mountpoint */ if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI)) mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; else if (label_chunk_info[i].type == PART_SWAP) mountpoint = "swap"; else mountpoint = ""; /* Now display the newfs field */ if (label_chunk_info[i].type == PART_FAT) strcpy(newfs, "DOS"); #if defined(__ia64__) else if (label_chunk_info[i].type == PART_EFI) { strcpy(newfs, "EFI"); if (label_chunk_info[i].c->private_data) { strcat(newfs, " "); PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; strcat(newfs, pi->do_newfs ? " Y" : " N"); } } #endif else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; switch (pi->newfs_type) { case NEWFS_UFS: strcpy(newfs, NEWFS_UFS_STRING); if (pi->newfs_data.newfs_ufs.ufs1) strcat(newfs, "1"); else strcat(newfs, "2"); if (pi->newfs_data.newfs_ufs.softupdates) strcat(newfs, "+S"); else strcat(newfs, " "); break; case NEWFS_MSDOS: strcpy(newfs, "FAT"); break; case NEWFS_CUSTOM: strcpy(newfs, "CUST"); break; } strcat(newfs, pi->do_newfs ? " Y" : " N "); } else if (label_chunk_info[i].type == PART_SWAP) strcpy(newfs, "SWAP"); else strcpy(newfs, "*"); for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) onestr[PART_MOUNT_COL + j] = mountpoint[j]; if (label_chunk_info[i].c->size == 0) - snprintf(num, 10, "%5ldMB", 0); + snprintf(num, 10, "%5dMB", 0); else if (label_chunk_info[i].c->size < (100 * ONE_GIG)) - snprintf(num, 10, "%5ldMB", - label_chunk_info[i].c->size / ONE_MEG); + snprintf(num, 10, "%5jdMB", + (intmax_t)label_chunk_info[i].c->size / ONE_MEG); else - snprintf(num, 10, "%5ldGB", - label_chunk_info[i].c->size / ONE_GIG); + snprintf(num, 10, "%5jdGB", + (intmax_t)label_chunk_info[i].c->size / ONE_GIG); memcpy(onestr + PART_SIZE_COL, num, strlen(num)); memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; if (i == label_focus) { label_focus_found = -1; wattrset(ChunkWin, A_BOLD); } if (i == here) wattrset(ChunkWin, ATTR_SELECTED); /*** lazy man's way of expensively padding this string ***/ while (strlen(onestr) < 37) strcat(onestr, " "); mvwaddstr(ChunkWin, prow, pcol, onestr); wattrset(ChunkWin, A_NORMAL); move(0, 0); ++prow; ++label_count; } } /*** this will erase all the extra stuff ***/ memset(clrmsg, ' ', 37); clrmsg[37] = '\0'; while (pslice_count < pslice_max) { mvprintw(srow++, 0, clrmsg); clrtoeol(); ++pslice_count; } while (label_count < (2 * (label_max - 1))) { mvwaddstr(ChunkWin, prow++, pcol, clrmsg); ++label_count; if (prow == (label_max - 1)) { prow = 0; pcol = PART_OFF; } } refresh(); wrefresh(ChunkWin); } static void print_command_summary(void) { mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); if (!RunningAsInit) mvprintw(18, 56, "W = Write"); mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates Z = Custom Newfs"); mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge"); mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } static void clear_wins(void) { extern void print_label_chunks(); clear(); print_label_chunks(); } static int diskLabel(Device *dev) { - int sz, key = 0; + daddr_t sz; + int key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; WINDOW *w = savescr(); label_focus = 0; pslice_focus = 0; here = 0; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); restorescr(w); return DITEM_FAILURE; } labeling = TRUE; keypad(stdscr, TRUE); record_label_chunks(devs, dev); clear(); while (labeling) { char *cp; int rflags = DELCHUNK_NORMAL; print_label_chunks(); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); clrtoeol(); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } refresh(); key = getch(); switch (toupper(key)) { int i; static char _msg[40]; case '\014': /* ^L */ clear_wins(); break; case '\020': /* ^P */ case KEY_UP: case '-': if (here != 0) --here; else while (label_chunk_info[here + 1].c) ++here; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (label_chunk_info[here + 1].c) ++here; else here = 0; break; case KEY_HOME: here = 0; break; case KEY_END: while (label_chunk_info[here + 1].c) ++here; break; case KEY_F(1): case '?': systemDisplayHelp("partition"); clear_wins(); break; case '1': if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if ((pi != NULL) && (pi->newfs_type == NEWFS_UFS)) { pi->newfs_data.newfs_ufs.ufs1 = true; } else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; break; case '2': if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if ((pi != NULL) && (pi->newfs_type == NEWFS_UFS)) { pi->newfs_data.newfs_ufs.ufs1 = false; } else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; break; case 'A': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a disk slice (at top of screen)"; break; } /* * Generate standard partitions automatically. If we do not * have sufficient space we attempt to scale-down the size * of the partitions within certain bounds. */ { int perc; int req = 0; for (perc = 100; perc > 0; perc -= 5) { req = 0; /* reset for each loop */ if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) break; } if (msg) { if (req) { msgConfirm(msg); clear_wins(); msg = NULL; } } } break; case 'C': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a master partition (see top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) { msg = "Not enough space to create an additional FreeBSD partition"; break; } else { char *val; - int size; + daddr_t size; struct chunk *tmp; char osize[80]; u_long flags = 0; - sprintf(osize, "%d", sz); + sprintf(osize, "%jd", (intmax_t)sz); val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing G for\n" #ifdef __ia64__ "gigabytes, M for megabytes.\n" #else "gigabytes, M for megabytes, or C for cylinders.\n" #endif - "%d blocks (%dMB) are free.", - sz, sz / ONE_MEG); - if (!val || (size = strtol(val, &cp, 0)) <= 0) { + "%jd blocks (%jdMB) are free.", + (intmax_t)sz, (intmax_t)sz / ONE_MEG); + if (!val || (size = strtoimax(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; else if (toupper(*cp) == 'G') size *= ONE_GIG; #ifndef __ia64__ else if (toupper(*cp) == 'C') size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); #endif } if (size <= FS_MIN_SIZE) { msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); clear_wins(); break; } type = get_partition_type(); if (type == PART_NONE) { clear_wins(); beep(); break; } if (type == PART_FILESYSTEM || type == PART_EFI) { if ((p = get_mountpoint(NULL)) == NULL) { clear_wins(); beep(); break; } else if (!strcmp(p->mountpoint, "/")) { if (type != PART_FILESYSTEM) { clear_wins(); beep(); break; } else flags |= CHUNK_IS_ROOT; } else flags &= ~CHUNK_IS_ROOT; } else p = NULL; if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { msgConfirm("Warning: This is smaller than the recommended size for a\n" "root partition. For a variety of reasons, root\n" "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, size, #ifdef __ia64__ (type == PART_EFI) ? efi : part, (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, #else part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, #endif flags); if (!tmp) { msgConfirm("Unable to create the partition. Too big?"); clear_wins(); break; } #ifdef __alpha__ /* * SRM requires that the root partition is at the * begining of the disk and cannot boot otherwise. * Warn Alpha users if they are about to shoot themselves in * the foot in this way. * * Since partitions may not start precisely at offset 0 we * check for a "close to 0" instead. :-( */ if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { msgConfirm("Your root partition `a' does not seem to be the first\n" "partition. The Alpha's firmware can only boot from the\n" "first partition. So it is unlikely that your current\n" "disk layout will be bootable boot after installation.\n" "\n" "Please allocate the root partition before allocating\n" "any others.\n"); } #endif /* alpha */ tmp->private_data = p; tmp->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); /* This is where we assign focus to new label so it shows. */ { int i; label_focus = -1; for (i = 0; label_chunk_info[i].c; ++i) { if (label_chunk_info[i].c == tmp) { label_focus = i; break; } } if (label_focus == -1) label_focus = i - 1; } } break; case KEY_DC: case 'R': /* recover space (delete w/ recover) */ /* * Delete the partition w/ space recovery. */ rflags = DELCHUNK_RECOVER; /* fall through */ case 'D': /* delete */ if (label_chunk_info[here].type == PART_SLICE) { msg = MSG_NOT_APPLICABLE; break; } else if (label_chunk_info[here].type == PART_FAT) { msg = "Use the Disk Partition Editor to delete DOS partitions"; break; } Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); break; case 'M': /* mount */ switch(label_chunk_info[here].type) { case PART_SLICE: msg = MSG_NOT_APPLICABLE; break; case PART_SWAP: msg = "You don't need to specify a mountpoint for a swap partition."; break; case PART_FAT: case PART_EFI: case PART_FILESYSTEM: oldp = label_chunk_info[here].c->private_data; p = get_mountpoint(label_chunk_info[here].c); if (p) { if (!oldp) p->do_newfs = FALSE; if ((label_chunk_info[here].type == PART_FAT || label_chunk_info[here].type == PART_EFI) && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") || !strcmp(p->mountpoint, "/var"))) { msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); strcpy(p->mountpoint, "/bogus"); } } if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); break; default: msgFatal("Bogus partition under cursor???"); break; } break; case 'N': /* Set newfs options */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) getNewfsOptionalArguments( label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; case 'S': /* Toggle soft updates flag */ if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (pi != NULL && pi->newfs_type == NEWFS_UFS) pi->newfs_data.newfs_ufs.softupdates = !pi->newfs_data.newfs_ufs.softupdates; else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; case 'T': /* Toggle newfs state */ if ((label_chunk_info[here].type == PART_FILESYSTEM) && (label_chunk_info[here].c->private_data)) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (!pi->do_newfs) label_chunk_info[here].c->flags |= CHUNK_NEWFS; else label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs : TRUE); if (pi != NULL && pi->newfs_type == NEWFS_UFS) { PartInfo *pi_new = label_chunk_info[here].c->private_data; pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; } safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } #if defined(__ia64__) else if (label_chunk_info[here].type == PART_EFI && label_chunk_info[here].c->private_data) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (!pi->do_newfs) label_chunk_info[here].c->flags |= CHUNK_NEWFS; else label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; label_chunk_info[here].c->private_data = new_efi_part(pi->mountpoint, !pi->do_newfs); safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } #endif else msg = MSG_NOT_APPLICABLE; break; case 'U': clear(); if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written out your changes -\n" "it's too late to undo!"); } else if (!msgNoYes("Are you SURE you want to Undo everything?")) { variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); for (i = 0; devs[i]; i++) { Disk *d; if (!devs[i]->enabled) continue; else if ((d = Open_Disk(devs[i]->name)) != NULL) { Free_Disk(devs[i]->private); devs[i]->private = d; #ifdef WITH_SLICES diskPartition(devs[i]); #endif } } record_label_chunks(devs, dev); } clear_wins(); break; case 'W': if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written out your changes - if you\n" "wish to overwrite them, you'll have to restart\n" "sysinstall first."); } else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_LABELLED, "yes", 0); diskLabelCommit(NULL); } clear_wins(); break; case 'Z': /* Set newfs command line */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) getNewfsCmd(label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; #ifndef __ia64__ case '|': if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" "This is an entirely undocumented feature which you are not\n" "expected to understand!")) { int i; Device **devs; dialog_clear(); end_dialog(); DialogActive = FALSE; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Can't find any disk devices!"); break; } for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { if (devs[i]->enabled) slice_wizard(((Disk *)devs[i]->private)); } if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); DialogActive = TRUE; record_label_chunks(devs, dev); clear_wins(); } else msg = "A most prudent choice!"; break; #endif case '\033': /* ESC */ case 'Q': labeling = FALSE; break; default: beep(); sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); msg = _msg; break; } if (label_chunk_info[here].type == PART_SLICE) pslice_focus = here; else label_focus = here; } restorescr(w); return DITEM_SUCCESS; } -static __inline int -requested_part_size(char *varName, int nom, int def, int perc) +static __inline daddr_t +requested_part_size(char *varName, daddr_t nom, int def, int perc) { char *cp; - int sz; + daddr_t sz; if ((cp = variable_get(varName)) != NULL) - sz = atoi(cp); + sz = strtoimax(cp, NULL, 0); else sz = nom + (def - nom) * perc / 100; return(sz * ONE_MEG); } /* * Attempt to auto-label the disk. 'perc' (0-100) scales * the size of the various partitions within appropriate * bounds (NOMINAL through DEFAULT sizes). The procedure * succeeds of NULL is returned. A non-null return message * is either a failure-status message (*req == 0), or * a confirmation requestor (*req == 1). *req is 0 on * entry to this call. * * We autolabel the following partitions: /, swap, /var, /tmp, /usr, * and /home. /home receives any extra left over disk space. */ static char * try_auto_label(Device **devs, Device *dev, int perc, int *req) { - int sz; + daddr_t sz; struct chunk *root_chunk = NULL; struct chunk *swap_chunk = NULL; struct chunk *usr_chunk = NULL; struct chunk *var_chunk = NULL; struct chunk *tmp_chunk = NULL; struct chunk *home_chunk = NULL; int mib[2]; unsigned long physmem; size_t size; Chunk *rootdev, *swapdev, *usrdev, *vardev; Chunk *tmpdev, *homedev; char *msg = NULL; sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) return("Not enough free space to create a new partition in the slice"); (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev, &tmpdev, &homedev); if (!rootdev) { sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); if (!root_chunk) { *req = 1; msg = "Unable to create the root partition. Too big?"; goto done; } root_chunk->private_data = new_part("/", TRUE); root_chunk->private_free = safe_free; root_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!swapdev) { sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); if (sz == 0) { - int nom; - int def; + daddr_t nom; + daddr_t def; mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); def = 2 * (int)(physmem / 512); if (def < SWAP_MIN_SIZE * ONE_MEG) def = SWAP_MIN_SIZE * ONE_MEG; if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; nom = (int)(physmem / 512) / 8; sz = nom + (def - nom) * perc / 100; } swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_SWAP, CHUNK_AUTO_SIZE); if (!swap_chunk) { *req = 1; msg = "Unable to create the swap partition. Too big?"; goto done; } swap_chunk->private_data = 0; swap_chunk->private_free = safe_free; record_label_chunks(devs, dev); } if (!vardev) { sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc); var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!var_chunk) { *req = 1; msg = "Not enough free space for /var - you will need to\n" "partition your disk manually with a custom install!"; goto done; } var_chunk->private_data = new_part("/var", TRUE); var_chunk->private_free = safe_free; var_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!tmpdev && !variable_get(VAR_NO_TMP)) { sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!tmp_chunk) { *req = 1; msg = "Not enough free space for /tmp - you will need to\n" "partition your disk manually with a custom install!"; goto done; } tmp_chunk->private_data = new_part("/tmp", TRUE); tmp_chunk->private_free = safe_free; tmp_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!usrdev && !variable_get(VAR_NO_USR)) { sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); #if AUTO_HOME == 0 sz = space_free(label_chunk_info[here].c); #endif if (sz) { if (sz < (USR_MIN_SIZE * ONE_MEG)) { *req = 1; msg = "Not enough free space for /usr - you will need to\n" "partition your disk manually with a custom install!"; } usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!usr_chunk) { msg = "Unable to create the /usr partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"; goto done; } usr_chunk->private_data = new_part("/usr", TRUE); usr_chunk->private_free = safe_free; usr_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } } #if AUTO_HOME == 1 if (!homedev && !variable_get(VAR_NO_HOME)) { sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); if (sz < space_free(label_chunk_info[here].c)) sz = space_free(label_chunk_info[here].c); if (sz) { if (sz < (HOME_MIN_SIZE * ONE_MEG)) { *req = 1; msg = "Not enough free space for /home - you will need to\n" "partition your disk manually with a custom install!"; goto done; } home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!home_chunk) { msg = "Unable to create the /home partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"; goto done; } home_chunk->private_data = new_part("/home", TRUE); home_chunk->private_free = safe_free; home_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } } #endif /* At this point, we're reasonably "labelled" */ if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); done: if (msg) { if (root_chunk) Delete_Chunk(root_chunk->disk, root_chunk); if (swap_chunk) Delete_Chunk(swap_chunk->disk, swap_chunk); if (var_chunk) Delete_Chunk(var_chunk->disk, var_chunk); if (tmp_chunk) Delete_Chunk(tmp_chunk->disk, tmp_chunk); if (usr_chunk) Delete_Chunk(usr_chunk->disk, usr_chunk); if (home_chunk) Delete_Chunk(home_chunk->disk, home_chunk); record_label_chunks(devs, dev); } return(msg); } static int diskLabelNonInteractive(Device *dev) { char *cp; PartType type; PartInfo *p; u_long flags; int i, status; Device **devs; Disk *d; status = DITEM_SUCCESS; cp = variable_get(VAR_DISK); if (!cp) { msgConfirm("diskLabel: No disk selected - can't label automatically."); return DITEM_FAILURE; } devs = deviceFind(cp, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("diskLabel: No disk device %s found!", cp); return DITEM_FAILURE; } if (dev) d = dev->private; else d = devs[0]->private; record_label_chunks(devs, dev); for (i = 0; label_chunk_info[i].c; i++) { Chunk *c1 = label_chunk_info[i].c; if (label_chunk_info[i].type == PART_SLICE) { char name[512]; char typ[10], mpoint[50]; int entries; for (entries = 1;; entries++) { - int sz, soft = 0; + intmax_t sz; + int soft = 0; snprintf(name, sizeof name, "%s-%d", c1->name, entries); if ((cp = variable_get(name)) == NULL) break; - if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) { + if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; break; } else { Chunk *tmp; flags = 0; if (!strcmp(typ, "swap")) { type = PART_SWAP; strcpy(mpoint, "SWAP"); } else { type = PART_FILESYSTEM; if (!strcmp(mpoint, "/")) flags |= CHUNK_IS_ROOT; } if (!sz) sz = space_free(c1); if (sz > space_free(c1)) { msgConfirm("Not enough free space to create partition: %s", mpoint); status = DITEM_FAILURE; break; } if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { msgConfirm("Unable to create from partition spec: %s. Too big?", cp); status = DITEM_FAILURE; break; } else { PartInfo *pi; pi = tmp->private_data = new_part(mpoint, TRUE); tmp->private_free = safe_free; pi->newfs_data.newfs_ufs.softupdates = soft; } } } } else { /* Must be something we can set a mountpoint for */ cp = variable_get(c1->name); if (cp) { char mpoint[50], do_newfs[8]; Boolean newfs = FALSE; do_newfs[0] = '\0'; if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; break; } newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; if (c1->private_data) { p = c1->private_data; p->do_newfs = newfs; strcpy(p->mountpoint, mpoint); } else { c1->private_data = new_part(mpoint, newfs); c1->private_free = safe_free; } if (!strcmp(mpoint, "/")) c1->flags |= CHUNK_IS_ROOT; else c1->flags &= ~CHUNK_IS_ROOT; } } } if (status == DITEM_SUCCESS) variable_set2(DISK_LABELLED, "yes", 0); return status; } diff --git a/usr.sbin/sysinstall/disks.c b/usr.sbin/sysinstall/disks.c index 4fba2c7df83b..535fb058373c 100644 --- a/usr.sbin/sysinstall/disks.c +++ b/usr.sbin/sysinstall/disks.c @@ -1,991 +1,996 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include +#include #include #include #ifdef WITH_SLICES enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; #ifdef PC98 #define SUBTYPE_FREEBSD 50324 #define SUBTYPE_FAT 37218 #else #define SUBTYPE_FREEBSD 165 #define SUBTYPE_FAT 6 #endif #define SUBTYPE_EFI 239 #ifdef PC98 #define OTHER_SLICE_VALUES \ "Other popular values are 37218 for a\n" \ "DOS FAT partition.\n\n" #else #define OTHER_SLICE_VALUES \ "Other popular values are 6 for a\n" \ "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ "130 for a Linux swap partition.\n\n" #endif #define NON_FREEBSD_NOTE \ "Note: If you choose a non-FreeBSD partition type, it will not\n" \ "be formatted or otherwise prepared, it will simply reserve space\n" \ "for you to use another tool, such as DOS format, to later format\n" \ "and actually use the partition." /* Where we start displaying chunk information on the screen */ #define CHUNK_START_ROW 5 /* Where we keep track of MBR chunks */ static struct chunk *chunk_info[16]; static int current_chunk; static void diskPartitionNonInteractive(Device *dev); static u_char * bootalloc(char *name, size_t *size); static void record_chunks(Disk *d) { struct chunk *c1 = NULL; int i = 0; - int last_free = 0; + daddr_t last_free = 0; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == unused && c1->size > last_free) { last_free = c1->size; current_chunk = i; } chunk_info[i++] = c1; } chunk_info[i] = NULL; if (current_chunk >= i) current_chunk = i - 1; } -static int Total; +static daddr_t Total; static void print_chunks(Disk *d, int u) { int row; int i; - int sz; + daddr_t sz; char *szstr; szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST"))); - for (i = Total = 0; chunk_info[i]; i++) + Total = 0; + for (i = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; #ifdef PC98 if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { #else if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { #endif dialog_clear_norefresh(); msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" "a more likely geometry. If this geometry is incorrect or you\n" "are unsure as to whether or not it's correct, please consult\n" "the Hardware Guide in the Documentation submenu or use the\n" "(G)eometry command to change it now.\n\n" "Remember: you need to enter whatever your BIOS thinks the\n" "geometry is! For IDE, it's what you were told in the BIOS\n" "setup. For SCSI, it's the translation mode your controller is\n" "using. Do NOT use a ``physical geometry''.", d->bios_cyl, d->bios_hd, d->bios_sect, d->name); Sanitize_Bios_Geom(d); } attrset(A_NORMAL); mvaddstr(0, 0, "Disk name:\t"); clrtobot(); attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); mvprintw(1, 0, - "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", + "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %jd sectors (%jdMB)", d->bios_cyl, d->bios_hd, d->bios_sect, - d->bios_cyl * d->bios_hd * d->bios_sect, - d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect, + (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", "Offset", "Size", szstr, "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { switch(u) { default: /* fall thru */ case UNIT_BLOCKS: sz = chunk_info[i]->size; break; case UNIT_KILO: sz = chunk_info[i]->size / (1024/512); break; case UNIT_MEG: sz = chunk_info[i]->size / (1024/512) / 1024; break; case UNIT_GIG: sz = chunk_info[i]->size / (1024/512) / 1024 / 1024; break; } if (i == current_chunk) attrset(ATTR_SELECTED); - mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", - chunk_info[i]->offset, sz, - chunk_info[i]->end, chunk_info[i]->name, + mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s", + (intmax_t)chunk_info[i]->offset, (intmax_t)sz, + (intmax_t)chunk_info[i]->end, chunk_info[i]->name, chunk_info[i]->type, slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); if (i == current_chunk) attrset(A_NORMAL); } } static void print_command_summary() { mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); if (!RunningAsInit) mvprintw(18, 47, "W = Write Changes"); mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } #ifdef PC98 static void getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, u_char **bootmenu, size_t *bootmenu_size) { static u_char *boot0; static size_t boot0_size; static u_char *boot05; static size_t boot05_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of IPL the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuIPLType.title = str; i = dmenuOpenSimple(&MenuIPLType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else BootMgr = 1; } if (cp || i) { switch (BootMgr) { case 0: if (!boot0) boot0 = bootalloc("boot0", &boot0_size); *bootipl = boot0; *bootipl_size = boot0_size; if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); *bootmenu = boot05; *bootmenu_size = boot05_size; return; case 1: default: break; } } *bootipl = NULL; *bootipl_size = 0; *bootmenu = NULL; *bootmenu_size = 0; } #else static void getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) { #if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ static u_char *mbr, *boot0; static size_t mbr_size, boot0_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else if (!strcmp(cp, "standard")) BootMgr = 1; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: if (!boot0) boot0 = bootalloc("boot0", &boot0_size); *bootCode = boot0; *bootCodeSize = boot0_size; return; case 1: if (!mbr) mbr = bootalloc("mbr", &mbr_size); *bootCode = mbr; *bootCodeSize = mbr_size; return; case 2: default: break; } } #endif *bootCode = NULL; *bootCodeSize = 0; } #endif #endif /* WITH_SLICES */ int diskGetSelectCount(Device ***devs) { int i, cnt, enabled; char *cp; Device **dp; cp = variable_get(VAR_DISK); dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(dp); if (!cnt) return -1; for (i = 0, enabled = 0; i < cnt; i++) { if (dp[i]->enabled) ++enabled; } return enabled; } #ifdef WITH_SLICES void diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif WINDOW *w = savescr(); Disk *d = (Disk *)dev->private; int size_unit; size_unit = UNIT_BLOCKS; chunking = TRUE; keypad(stdscr, TRUE); /* Flush both the dialog and curses library views of the screen since we don't always know who called us */ dialog_clear_norefresh(), clear(); current_chunk = 0; /* Set up the chunk array */ record_chunks(d); while (chunking) { char *val, geometry[80]; /* Now print our overall state */ if (d) print_chunks(d, size_unit); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } /* Get command character */ key = getch(); switch (toupper(key)) { case '\014': /* ^L (redraw) */ clear(); msg = NULL; break; case '\020': /* ^P */ case KEY_UP: case '-': if (current_chunk != 0) --current_chunk; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_HOME: current_chunk = 0; break; case KEY_END: while (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_F(1): case '?': systemDisplayHelp("slice"); clear(); break; case 'A': case 'F': /* Undocumented magic Dangerously Dedicated mode */ #if !defined(__i386__) && !defined(__amd64__) && !defined(__ia64__) rv = 1; #else /* The rest is only relevant on x86 */ cp = variable_get(VAR_DEDICATE_DISK); if (cp && !strcasecmp(cp, "always")) rv = 1; else if (toupper(key) == 'A') rv = 0; else { rv = msgYesNo("Do you want to do this with a true partition entry\n" "so as to remain cooperative with any future possible\n" "operating systems on the drive(s)?\n" "(See also the section about ``dangerously dedicated''\n" "disks in the FreeBSD FAQ.)"); if (rv == -1) rv = 0; } #endif All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); clear(); break; case 'C': if (chunk_info[current_chunk]->type != unused) msg = "Slice in use, delete it first or move to an unused one."; else { char *val, tmp[20], name[16], *cp; - int size, subtype; + daddr_t size; + int subtype; chunk_e partitiontype; #ifdef PC98 snprintf(name, sizeof (name), "%s", "FreeBSD"); val = msgGetInput(name, "Please specify the name for new FreeBSD slice."); if (val) strncpy(name, val, sizeof (name)); #else name[0] = '\0'; #endif - snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); + snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size); val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" "or append a trailing `M' for megabytes (e.g. 20M)."); - if (val && (size = strtol(val, &cp, 0)) > 0) { + if (val && (size = strtoimax(val, &cp, 0)) > 0) { if (*cp && toupper(*cp) == 'M') size *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') size *= ONE_GIG; sprintf(tmp, "%d", SUBTYPE_FREEBSD); val = msgGetInput(tmp, "Enter type of partition to create:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type %u). " OTHER_SLICE_VALUES NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else if (subtype == SUBTYPE_EFI) partitiontype = efi; else #ifdef PC98 partitiontype = pc98; #else partitiontype = mbr; #endif Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } } clear(); } break; case KEY_DC: case 'D': if (chunk_info[current_chunk]->type == unused) msg = "Slice is already unused!"; else { Delete_Chunk(d, chunk_info[current_chunk]); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } break; case 'T': if (chunk_info[current_chunk]->type == unused) msg = "Slice is currently unused (use create instead)"; else { char *val, tmp[20]; int subtype; chunk_e partitiontype; sprintf(tmp, "%d", chunk_info[current_chunk]->subtype); val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will use the current type. To choose a native\n" "FreeBSD slice enter %u. " OTHER_SLICE_VALUES NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else if (subtype == SUBTYPE_EFI) partitiontype = efi; else #ifdef PC98 partitiontype = pc98; #else partitiontype = mbr; #endif chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } } break; case 'G': snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" "Don't forget to use the two slash (/) separator characters!\n" "It's not possible to parse the field without them."); if (val) { long nc, nh, ns; nc = strtol(val, &val, 0); nh = strtol(val + 1, &val, 0); ns = strtol(val + 1, 0, 0); Set_Bios_Geom(d, nc, nh, ns); } clear(); break; case 'S': /* Set Bootable */ chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; break; case 'U': if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written this information out - you\n" "can't undo it."); } else if (!msgNoYes("Are you SURE you want to Undo everything?")) { char cp[BUFSIZ]; sstrncpy(cp, d->name, sizeof cp); Free_Disk(dev->private); d = Open_Disk(cp); if (!d) msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); dev->private = d; variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); if (d) record_chunks(d); } clear(); break; case 'W': if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions. If you're adding a disk, you should NOT write\n" "from this screen, you should do it from the label editor.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_PARTITIONED, "yes", 0); #ifdef PC98 /* * Don't trash the IPL if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested a FreeBSD Boot Manager -- both would be fatal in * this case. */ /* * Don't offer to update the IPL on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); else { bootipl = NULL; bootipl_size = 0; bootmenu = NULL; bootmenu_size = 0; } Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested booteasy or a "standard" MBR -- both would be * fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &mbrContents, &mbrSize); else { mbrContents = NULL; mbrSize = 0; } Set_Boot_Mgr(d, mbrContents, mbrSize); #endif if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) msgConfirm("Disk partition write returned an error status!"); else msgConfirm("Wrote FDISK partition information out successfully."); } clear(); break; #ifndef __ia64__ case '|': if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } else msg = "Wise choice!"; clear(); break; #endif case '\033': /* ESC */ case 'Q': chunking = FALSE; #ifdef PC98 /* * Don't trash the IPL if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * a FreeBSD Boot Manager -- both would be fatal in this case. */ /* * Don't offer to update the IPL on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { if (variable_cmp(DISK_PARTITIONED, "written")) { getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); } } #else /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * booteasy or a "standard" MBR -- both would be fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { if (variable_cmp(DISK_PARTITIONED, "written")) { getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); } } #endif break; case 'Z': size_unit = (size_unit + 1) % UNIT_SIZE; break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; use_helpline("Press F1 to read more about disk slices."); use_helpfile(systemHelpFile("partition", buf)); if (!variable_get(VAR_NO_WARN)) dialog_mesgbox("Disk slicing warning:", p, -1, -1); free(p); } restorescr(w); } #endif /* WITH_SLICES */ static u_char * bootalloc(char *name, size_t *size) { char buf[FILENAME_MAX]; struct stat sb; snprintf(buf, sizeof buf, "/boot/%s", name); if (stat(buf, &sb) != -1) { int fd; fd = open(buf, O_RDONLY); if (fd != -1) { u_char *cp; cp = malloc(sb.st_size); if (read(fd, cp, sb.st_size) != sb.st_size) { free(cp); close(fd); msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); return NULL; } close(fd); if (size != NULL) *size = sb.st_size; return cp; } msgDebug("bootalloc: couldn't open %s\n", buf); } else msgDebug("bootalloc: can't stat %s\n", buf); return NULL; } #ifdef WITH_SLICES static int partitionHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskPartition(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int partitionCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskPartitionEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt, devcnt; cnt = diskGetSelectCount(&devs); devcnt = deviceCount(devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ for (i = 0; i < devcnt; i++) { if (devs[i]->enabled) { if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) diskPartitionNonInteractive(devs[i]); else diskPartition(devs[i]); } } } else { /* No disks are selected, fall-back case now */ if (devcnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) diskPartitionNonInteractive(devs[0]); else diskPartition(devs[0]); return DITEM_SUCCESS; } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); return DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } return i; } } return DITEM_SUCCESS; } #endif /* WITH_SLICES */ int diskPartitionWrite(dialogMenuItem *self) { Device **devs; int i; if (!variable_cmp(DISK_PARTITIONED, "written")) return DITEM_SUCCESS; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find any disks to write to??"); return DITEM_FAILURE; } if (isDebug()) msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); for (i = 0; devs[i]; i++) { Disk *d = (Disk *)devs[i]->private; static u_char *boot1; #if defined(__i386__) || defined(__ia64__) || defined(__amd64__) static u_char *boot2; #endif if (!devs[i]->enabled) continue; #if defined(__i386__) || defined(__amd64__) if (!boot1) boot1 = bootalloc("boot1", NULL); if (!boot2) boot2 = bootalloc("boot2", NULL); Set_Boot_Blocks(d, boot1, boot2); #elif !defined(__ia64__) if (!boot1) boot1 = bootalloc("boot1", NULL); Set_Boot_Blocks(d, boot1, NULL); #endif msgNotify("Writing partition information to drive %s", d->name); if (!Fake && Write_Disk(d)) { msgConfirm("ERROR: Unable to write data to disk %s!", d->name); return DITEM_FAILURE; } } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written", 0); return DITEM_SUCCESS | DITEM_RESTORE; } #ifdef WITH_SLICES /* Partition a disk based wholly on which variables are set */ static void diskPartitionNonInteractive(Device *dev) { char *cp; - int i, sz, all_disk = 0; + int i, all_disk = 0; + daddr_t sz; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif Disk *d = (Disk *)dev->private; record_chunks(d); cp = variable_get(VAR_GEOMETRY); if (cp) { msgDebug("Setting geometry from script to: %s\n", cp); d->bios_cyl = strtol(cp, &cp, 0); d->bios_hd = strtol(cp + 1, &cp, 0); d->bios_sect = strtol(cp + 1, 0, 0); } cp = variable_get(VAR_PARTITION); if (cp) { if (!strcmp(cp, "free")) { /* Do free disk space case */ for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least 10MB in size, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find any free space on this disk!"); return; } } else if (!strcmp(cp, "all")) { /* Do all disk space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, FALSE); } else if (!strcmp(cp, "exclusive")) { /* Do really-all-the-disk-space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, all_disk = TRUE); } - else if ((sz = strtol(cp, &cp, 0))) { + else if ((sz = strtoimax(cp, &cp, 0))) { /* Look for sz bytes free */ if (*cp && toupper(*cp) == 'M') sz *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') sz *= ONE_GIG; for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least sz MB, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { - msgConfirm("Unable to find %d free blocks on this disk!", sz); + msgConfirm("Unable to find %jd free blocks on this disk!", + (intmax_t)sz); return; } } else if (!strcmp(cp, "existing")) { /* Do existing FreeBSD case */ for (i = 0; chunk_info[i]; i++) { if (chunk_info[i]->type == freebsd) break; } if (!chunk_info[i]) { msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } variable_set2(DISK_PARTITIONED, "yes", 0); } } #endif /* WITH_SLICES */ diff --git a/usr.sbin/sysinstall/label.c b/usr.sbin/sysinstall/label.c index 5b4a51c5a2ca..e75da48dc86b 100644 --- a/usr.sbin/sysinstall/label.c +++ b/usr.sbin/sysinstall/label.c @@ -1,1671 +1,1676 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include +#include #include #include #include #define AUTO_HOME 0 /* do not create /home automatically */ /* * Everything to do with editing the contents of disk labels. */ /* A nice message we use a lot in the disklabel editor */ #define MSG_NOT_APPLICABLE "That option is not applicable here" /* Where to start printing the freebsd slices */ #define CHUNK_SLICE_START_ROW 2 #define CHUNK_PART_START_ROW 11 /* The smallest filesystem we're willing to create */ #define FS_MIN_SIZE ONE_MEG /* * Minimum partition sizes */ #if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) || defined(__amd64__) #define ROOT_MIN_SIZE 128 #else #define ROOT_MIN_SIZE 118 #endif #define SWAP_MIN_SIZE 32 #define USR_MIN_SIZE 80 #define VAR_MIN_SIZE 20 #define TMP_MIN_SIZE 20 #define HOME_MIN_SIZE 20 /* * Swap size limit for auto-partitioning (4G). */ #define SWAP_AUTO_LIMIT_SIZE 4096 /* * Default partition sizes. If we do not have sufficient disk space * for this configuration we scale things relative to the NOM vs DEFAULT * sizes. If the disk is larger then /home will get any remaining space. */ #define ROOT_DEFAULT_SIZE 256 #define USR_DEFAULT_SIZE 3072 #define VAR_DEFAULT_SIZE 256 #define TMP_DEFAULT_SIZE 256 #define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE /* * Nominal partition sizes. These are used to scale the default sizes down * when we have insufficient disk space. If this isn't sufficient we scale * down using the MIN sizes instead. */ #define ROOT_NOMINAL_SIZE 192 #define USR_NOMINAL_SIZE 512 #define VAR_NOMINAL_SIZE 64 #define TMP_NOMINAL_SIZE 64 #define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE /* The bottom-most row we're allowed to scribble on */ #define CHUNK_ROW_MAX 16 /* All the chunks currently displayed on the screen */ static struct { struct chunk *c; PartType type; } label_chunk_info[MAX_CHUNKS + 1]; static int here; /*** with this value we try to track the most recently added label ***/ static int label_focus = 0, pslice_focus = 0; static int diskLabel(Device *dev); static int diskLabelNonInteractive(Device *dev); static char *try_auto_label(Device **devs, Device *dev, int perc, int *req); static int labelHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskLabel(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int labelCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskLabelEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt; i = 0; cnt = diskGetSelectCount(&devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) i = diskLabelNonInteractive(NULL); else i = diskLabel(NULL); } else { /* No disks are selected, fall-back case now */ cnt = deviceCount(devs); if (cnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_DISKINTERACTIVE)) i = diskLabelNonInteractive(devs[0]); else i = diskLabel(devs[0]); } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); i = DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } } } if (DITEM_STATUS(i) != DITEM_FAILURE) { if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } return i; } int diskLabelCommit(dialogMenuItem *self) { char *cp; int i; /* Already done? */ if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) i = DITEM_SUCCESS; else if (!cp) { msgConfirm("You must assign disk labels before this option can be used."); i = DITEM_FAILURE; } /* The routine will guard against redundant writes, just as this one does */ else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else { msgInfo("All filesystem information written successfully."); variable_set2(DISK_LABELLED, "written", 0); i = DITEM_SUCCESS; } return i; } /* See if we're already using a desired partition name */ static Boolean check_conflict(char *name) { int i; for (i = 0; label_chunk_info[i].c; i++) if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) return TRUE; return FALSE; } /* How much space is in this FreeBSD slice? */ -static int +static daddr_t space_free(struct chunk *c) { struct chunk *c1; - int sz = c->size; + daddr_t sz = c->size; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) sz -= c1->size; } if (sz < 0) msgFatal("Partitions are larger than actual chunk??"); return sz; } /* Snapshot the current situation into the displayed chunks structure */ static void record_label_chunks(Device **devs, Device *dev) { int i, j, p; struct chunk *c1, *c2; Disk *d; j = p = 0; /* First buzz through and pick up the FreeBSD slices */ for (i = 0; devs[i]; i++) { if ((dev && devs[i] != dev) || !devs[i]->enabled) continue; d = (Disk *)devs[i]->private; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); #ifdef __ia64__ label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = d->chunks; j++; #endif /* Put the slice entries first */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = c1; ++j; } } } /* Now run through again and get the FreeBSD partition entries */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; d = (Disk *)devs[i]->private; /* Then buzz through and pick up the partitions */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part) { if (c2->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c2; ++j; } } } else if (c1->type == fat) { label_chunk_info[j].type = PART_FAT; label_chunk_info[j].c = c1; ++j; } #ifdef __ia64__ else if (c1->type == efi) { label_chunk_info[j].type = PART_EFI; label_chunk_info[j].c = c1; ++j; } else if (c1->type == part) { if (c1->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c1; ++j; } #endif } } label_chunk_info[j].c = NULL; if (here >= j) { here = j ? j - 1 : 0; } } /* A new partition entry */ static PartInfo * new_part(char *mpoint, Boolean newfs) { PartInfo *pi; if (!mpoint) mpoint = "/change_me"; pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); pi->do_newfs = newfs; pi->newfs_type = NEWFS_UFS; strcpy(pi->newfs_data.newfs_ufs.user_options, ""); pi->newfs_data.newfs_ufs.acls = FALSE; pi->newfs_data.newfs_ufs.multilabel = FALSE; pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/"); #ifdef PC98 pi->newfs_data.newfs_ufs.ufs1 = TRUE; #else pi->newfs_data.newfs_ufs.ufs1 = FALSE; #endif return pi; } #if defined(__ia64__) static PartInfo * new_efi_part(char *mpoint, Boolean newfs) { PartInfo *pi; if (!mpoint) mpoint = "/efi"; pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); pi->do_newfs = newfs; pi->newfs_type = NEWFS_MSDOS; return pi; } #endif /* Get the mountpoint for a partition and save it away */ static PartInfo * get_mountpoint(struct chunk *old) { char *val; PartInfo *tmp; Boolean newfs; if (old && old->private_data) tmp = old->private_data; else tmp = NULL; val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); if (!val || !*val) { if (!old) return NULL; else { free(old->private_data); old->private_data = NULL; } return NULL; } /* Is it just the same value? */ if (tmp && !strcmp(tmp->mountpoint, val)) return NULL; /* Did we use it already? */ if (check_conflict(val)) { msgConfirm("You already have a mount point for %s assigned!", val); return NULL; } /* Is it bogus? */ if (*val != '/') { msgConfirm("Mount point must start with a / character"); return NULL; } /* Is it going to be mounted on root? */ if (!strcmp(val, "/")) { if (old) old->flags |= CHUNK_IS_ROOT; } else if (old) old->flags &= ~CHUNK_IS_ROOT; newfs = TRUE; if (tmp) { newfs = tmp->do_newfs; safe_free(tmp); } val = string_skipwhite(string_prune(val)); tmp = new_part(val, newfs); if (old) { old->private_data = tmp; old->private_free = safe_free; } return tmp; } /* Get the type of the new partiton */ static PartType get_partition_type(void) { char selection[20]; int i; static unsigned char *fs_types[] = { #ifdef __ia64__ "EFI", "An EFI system partition", #endif "FS", "A file system", "Swap", "A swap partition.", }; WINDOW *w = savescr(); i = dialog_menu("Please choose a partition type", "If you want to use this partition for swap space, select Swap.\n" "If you want to put a filesystem on it, choose FS.", -1, -1, #ifdef __ia64__ 3, 3, #else 2, 2, #endif fs_types, selection, NULL, NULL); restorescr(w); if (!i) { #ifdef __ia64__ if (!strcmp(selection, "EFI")) return PART_EFI; #endif if (!strcmp(selection, "FS")) return PART_FILESYSTEM; else if (!strcmp(selection, "Swap")) return PART_SWAP; } return PART_NONE; } /* If the user wants a special newfs command for this, set it */ static void getNewfsCmd(PartInfo *p) { char buffer[NEWFS_CMD_ARGS_MAX]; char *val; switch (p->newfs_type) { case NEWFS_UFS: snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s", NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ? "-U" : "", p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", p->newfs_data.newfs_ufs.user_options); break; case NEWFS_MSDOS: snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD); break; case NEWFS_CUSTOM: strcpy(buffer, p->newfs_data.newfs_custom.command); break; } val = msgGetInput(buffer, "Please enter the newfs command and options you'd like to use in\n" "creating this file system."); if (val != NULL) { p->newfs_type = NEWFS_CUSTOM; strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX); } } static void getNewfsOptionalArguments(PartInfo *p) { char buffer[NEWFS_CMD_ARGS_MAX]; char *val; /* Must be UFS, per argument checking in I/O routines. */ strlcpy(buffer, p->newfs_data.newfs_ufs.user_options, NEWFS_CMD_ARGS_MAX); val = msgGetInput(buffer, "Please enter any additional UFS newfs options you'd like to\n" "use in creating this file system."); if (val != NULL) strlcpy(p->newfs_data.newfs_ufs.user_options, val, NEWFS_CMD_ARGS_MAX); } #define MAX_MOUNT_NAME 9 #define PART_PART_COL 0 #define PART_MOUNT_COL 10 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 8) #define PART_OFF 38 #define TOTAL_AVAIL_LINES (10) #define PSLICE_SHOWABLE (4) /* stick this all up on the screen */ static void print_label_chunks(void) { - int i, j, spaces, srow, prow, pcol; - int sz; + int i, j, srow, prow, pcol; + daddr_t sz; char clrmsg[80]; int ChunkPartStartRow; WINDOW *ChunkWin; /********************************************************/ /*** These values are for controling screen resources ***/ /*** Each label line holds up to 2 labels, so beware! ***/ /*** strategy will be to try to always make sure the ***/ /*** highlighted label is in the active display area. ***/ /********************************************************/ int pslice_max, label_max; int pslice_count, label_count, label_focus_found, pslice_focus_found; attrset(A_REVERSE); mvaddstr(0, 25, "FreeBSD Disklabel Editor"); attrset(A_NORMAL); /*** Count the number of parition slices ***/ pslice_count = 0; for (i = 0; label_chunk_info[i].c ; i++) { if (label_chunk_info[i].type == PART_SLICE) ++pslice_count; } pslice_max = pslice_count; /*** 4 line max for partition slices ***/ if (pslice_max > PSLICE_SHOWABLE) { pslice_max = PSLICE_SHOWABLE; } ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; /*** View partition slices modulo pslice_max ***/ label_max = TOTAL_AVAIL_LINES - pslice_max; for (i = 0; i < 2; i++) { mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); } srow = CHUNK_SLICE_START_ROW; prow = 0; pcol = 0; /*** these variables indicate that the focused item is shown currently ***/ label_focus_found = 0; pslice_focus_found = 0; label_count = 0; pslice_count = 0; mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); wclear(ChunkWin); /*** wrefresh(ChunkWin); ***/ for (i = 0; label_chunk_info[i].c; i++) { /* Is it a slice entry displayed at the top? */ if (label_chunk_info[i].type == PART_SLICE) { /*** This causes the new pslice to replace the previous display ***/ /*** focus must remain on the most recently active pslice ***/ if (pslice_count == pslice_max) { if (pslice_focus_found) { /*** This is where we can mark the more following ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); attrset(A_NORMAL); continue; } else { /*** this is where we set the more previous ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); attrset(A_NORMAL); pslice_count = 0; srow = CHUNK_SLICE_START_ROW; } } sz = space_free(label_chunk_info[i].c); if (i == here) attrset(ATTR_SELECTED); if (i == pslice_focus) pslice_focus_found = -1; if (label_chunk_info[i].c->type == whole) { if (sz >= 100 * ONE_GIG) mvprintw(srow++, 0, - "Disk: %s\t\tFree: %d blocks (%dGB)", - label_chunk_info[i].c->disk->name, sz, (sz / ONE_GIG)); + "Disk: %s\t\tFree: %jd blocks (%jdGB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_GIG)); else mvprintw(srow++, 0, - "Disk: %s\t\tFree: %d blocks (%dMB)", - label_chunk_info[i].c->disk->name, sz, (sz / ONE_MEG)); + "Disk: %s\t\tFree: %jd blocks (%jdMB)", + label_chunk_info[i].c->disk->name, (intmax_t)sz, + (intmax_t)(sz / ONE_MEG)); } else { if (sz >= 100 * ONE_GIG) mvprintw(srow++, 0, - "Disk: %s\tPartition name: %s\tFree: %d blocks (%dGB)", + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, - sz, (sz / ONE_GIG)); + (intmax_t)sz, (intmax_t)(sz / ONE_GIG)); else mvprintw(srow++, 0, - "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", + "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, - sz, (sz / ONE_MEG)); + (intmax_t)sz, (intmax_t)(sz / ONE_MEG)); } attrset(A_NORMAL); clrtoeol(); move(0, 0); /*** refresh(); ***/ ++pslice_count; } /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ else { char onestr[PART_OFF], num[10], *mountpoint, newfs[12]; /* * We copy this into a blank-padded string so that it looks like * a solid bar in reverse-video */ memset(onestr, ' ', PART_OFF - 1); onestr[PART_OFF - 1] = '\0'; /*** Track how many labels have been displayed ***/ if (label_count == ((label_max - 1 ) * 2)) { if (label_focus_found) { continue; } else { label_count = 0; prow = 0; pcol = 0; } } /* Go for two columns if we've written one full columns worth */ /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ if (label_count == label_max - 1) { pcol = PART_OFF; prow = 0; } memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); /* If it's a filesystem, display the mountpoint */ if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI)) mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; else if (label_chunk_info[i].type == PART_SWAP) mountpoint = "swap"; else mountpoint = ""; /* Now display the newfs field */ if (label_chunk_info[i].type == PART_FAT) strcpy(newfs, "DOS"); #if defined(__ia64__) else if (label_chunk_info[i].type == PART_EFI) { strcpy(newfs, "EFI"); if (label_chunk_info[i].c->private_data) { strcat(newfs, " "); PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; strcat(newfs, pi->do_newfs ? " Y" : " N"); } } #endif else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; switch (pi->newfs_type) { case NEWFS_UFS: strcpy(newfs, NEWFS_UFS_STRING); if (pi->newfs_data.newfs_ufs.ufs1) strcat(newfs, "1"); else strcat(newfs, "2"); if (pi->newfs_data.newfs_ufs.softupdates) strcat(newfs, "+S"); else strcat(newfs, " "); break; case NEWFS_MSDOS: strcpy(newfs, "FAT"); break; case NEWFS_CUSTOM: strcpy(newfs, "CUST"); break; } strcat(newfs, pi->do_newfs ? " Y" : " N "); } else if (label_chunk_info[i].type == PART_SWAP) strcpy(newfs, "SWAP"); else strcpy(newfs, "*"); for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) onestr[PART_MOUNT_COL + j] = mountpoint[j]; if (label_chunk_info[i].c->size == 0) - snprintf(num, 10, "%5ldMB", 0); + snprintf(num, 10, "%5dMB", 0); else if (label_chunk_info[i].c->size < (100 * ONE_GIG)) - snprintf(num, 10, "%5ldMB", - label_chunk_info[i].c->size / ONE_MEG); + snprintf(num, 10, "%5jdMB", + (intmax_t)label_chunk_info[i].c->size / ONE_MEG); else - snprintf(num, 10, "%5ldGB", - label_chunk_info[i].c->size / ONE_GIG); + snprintf(num, 10, "%5jdGB", + (intmax_t)label_chunk_info[i].c->size / ONE_GIG); memcpy(onestr + PART_SIZE_COL, num, strlen(num)); memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; if (i == label_focus) { label_focus_found = -1; wattrset(ChunkWin, A_BOLD); } if (i == here) wattrset(ChunkWin, ATTR_SELECTED); /*** lazy man's way of expensively padding this string ***/ while (strlen(onestr) < 37) strcat(onestr, " "); mvwaddstr(ChunkWin, prow, pcol, onestr); wattrset(ChunkWin, A_NORMAL); move(0, 0); ++prow; ++label_count; } } /*** this will erase all the extra stuff ***/ memset(clrmsg, ' ', 37); clrmsg[37] = '\0'; while (pslice_count < pslice_max) { mvprintw(srow++, 0, clrmsg); clrtoeol(); ++pslice_count; } while (label_count < (2 * (label_max - 1))) { mvwaddstr(ChunkWin, prow++, pcol, clrmsg); ++label_count; if (prow == (label_max - 1)) { prow = 0; pcol = PART_OFF; } } refresh(); wrefresh(ChunkWin); } static void print_command_summary(void) { mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); if (!RunningAsInit) mvprintw(18, 56, "W = Write"); mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates Z = Custom Newfs"); mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge"); mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } static void clear_wins(void) { extern void print_label_chunks(); clear(); print_label_chunks(); } static int diskLabel(Device *dev) { - int sz, key = 0; + daddr_t sz; + int key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; WINDOW *w = savescr(); label_focus = 0; pslice_focus = 0; here = 0; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); restorescr(w); return DITEM_FAILURE; } labeling = TRUE; keypad(stdscr, TRUE); record_label_chunks(devs, dev); clear(); while (labeling) { char *cp; int rflags = DELCHUNK_NORMAL; print_label_chunks(); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); clrtoeol(); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } refresh(); key = getch(); switch (toupper(key)) { int i; static char _msg[40]; case '\014': /* ^L */ clear_wins(); break; case '\020': /* ^P */ case KEY_UP: case '-': if (here != 0) --here; else while (label_chunk_info[here + 1].c) ++here; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (label_chunk_info[here + 1].c) ++here; else here = 0; break; case KEY_HOME: here = 0; break; case KEY_END: while (label_chunk_info[here + 1].c) ++here; break; case KEY_F(1): case '?': systemDisplayHelp("partition"); clear_wins(); break; case '1': if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if ((pi != NULL) && (pi->newfs_type == NEWFS_UFS)) { pi->newfs_data.newfs_ufs.ufs1 = true; } else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; break; case '2': if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if ((pi != NULL) && (pi->newfs_type == NEWFS_UFS)) { pi->newfs_data.newfs_ufs.ufs1 = false; } else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; break; case 'A': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a disk slice (at top of screen)"; break; } /* * Generate standard partitions automatically. If we do not * have sufficient space we attempt to scale-down the size * of the partitions within certain bounds. */ { int perc; int req = 0; for (perc = 100; perc > 0; perc -= 5) { req = 0; /* reset for each loop */ if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) break; } if (msg) { if (req) { msgConfirm(msg); clear_wins(); msg = NULL; } } } break; case 'C': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a master partition (see top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) { msg = "Not enough space to create an additional FreeBSD partition"; break; } else { char *val; - int size; + daddr_t size; struct chunk *tmp; char osize[80]; u_long flags = 0; - sprintf(osize, "%d", sz); + sprintf(osize, "%jd", (intmax_t)sz); val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing G for\n" #ifdef __ia64__ "gigabytes, M for megabytes.\n" #else "gigabytes, M for megabytes, or C for cylinders.\n" #endif - "%d blocks (%dMB) are free.", - sz, sz / ONE_MEG); - if (!val || (size = strtol(val, &cp, 0)) <= 0) { + "%jd blocks (%jdMB) are free.", + (intmax_t)sz, (intmax_t)sz / ONE_MEG); + if (!val || (size = strtoimax(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; else if (toupper(*cp) == 'G') size *= ONE_GIG; #ifndef __ia64__ else if (toupper(*cp) == 'C') size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); #endif } if (size <= FS_MIN_SIZE) { msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); clear_wins(); break; } type = get_partition_type(); if (type == PART_NONE) { clear_wins(); beep(); break; } if (type == PART_FILESYSTEM || type == PART_EFI) { if ((p = get_mountpoint(NULL)) == NULL) { clear_wins(); beep(); break; } else if (!strcmp(p->mountpoint, "/")) { if (type != PART_FILESYSTEM) { clear_wins(); beep(); break; } else flags |= CHUNK_IS_ROOT; } else flags &= ~CHUNK_IS_ROOT; } else p = NULL; if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { msgConfirm("Warning: This is smaller than the recommended size for a\n" "root partition. For a variety of reasons, root\n" "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, size, #ifdef __ia64__ (type == PART_EFI) ? efi : part, (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, #else part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, #endif flags); if (!tmp) { msgConfirm("Unable to create the partition. Too big?"); clear_wins(); break; } #ifdef __alpha__ /* * SRM requires that the root partition is at the * begining of the disk and cannot boot otherwise. * Warn Alpha users if they are about to shoot themselves in * the foot in this way. * * Since partitions may not start precisely at offset 0 we * check for a "close to 0" instead. :-( */ if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { msgConfirm("Your root partition `a' does not seem to be the first\n" "partition. The Alpha's firmware can only boot from the\n" "first partition. So it is unlikely that your current\n" "disk layout will be bootable boot after installation.\n" "\n" "Please allocate the root partition before allocating\n" "any others.\n"); } #endif /* alpha */ tmp->private_data = p; tmp->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); /* This is where we assign focus to new label so it shows. */ { int i; label_focus = -1; for (i = 0; label_chunk_info[i].c; ++i) { if (label_chunk_info[i].c == tmp) { label_focus = i; break; } } if (label_focus == -1) label_focus = i - 1; } } break; case KEY_DC: case 'R': /* recover space (delete w/ recover) */ /* * Delete the partition w/ space recovery. */ rflags = DELCHUNK_RECOVER; /* fall through */ case 'D': /* delete */ if (label_chunk_info[here].type == PART_SLICE) { msg = MSG_NOT_APPLICABLE; break; } else if (label_chunk_info[here].type == PART_FAT) { msg = "Use the Disk Partition Editor to delete DOS partitions"; break; } Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); break; case 'M': /* mount */ switch(label_chunk_info[here].type) { case PART_SLICE: msg = MSG_NOT_APPLICABLE; break; case PART_SWAP: msg = "You don't need to specify a mountpoint for a swap partition."; break; case PART_FAT: case PART_EFI: case PART_FILESYSTEM: oldp = label_chunk_info[here].c->private_data; p = get_mountpoint(label_chunk_info[here].c); if (p) { if (!oldp) p->do_newfs = FALSE; if ((label_chunk_info[here].type == PART_FAT || label_chunk_info[here].type == PART_EFI) && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") || !strcmp(p->mountpoint, "/var"))) { msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); strcpy(p->mountpoint, "/bogus"); } } if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); break; default: msgFatal("Bogus partition under cursor???"); break; } break; case 'N': /* Set newfs options */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) getNewfsOptionalArguments( label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; case 'S': /* Toggle soft updates flag */ if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (pi != NULL && pi->newfs_type == NEWFS_UFS) pi->newfs_data.newfs_ufs.softupdates = !pi->newfs_data.newfs_ufs.softupdates; else msg = MSG_NOT_APPLICABLE; } else msg = MSG_NOT_APPLICABLE; break; case 'T': /* Toggle newfs state */ if ((label_chunk_info[here].type == PART_FILESYSTEM) && (label_chunk_info[here].c->private_data)) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (!pi->do_newfs) label_chunk_info[here].c->flags |= CHUNK_NEWFS; else label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs : TRUE); if (pi != NULL && pi->newfs_type == NEWFS_UFS) { PartInfo *pi_new = label_chunk_info[here].c->private_data; pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; } safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } #if defined(__ia64__) else if (label_chunk_info[here].type == PART_EFI && label_chunk_info[here].c->private_data) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); if (!pi->do_newfs) label_chunk_info[here].c->flags |= CHUNK_NEWFS; else label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; label_chunk_info[here].c->private_data = new_efi_part(pi->mountpoint, !pi->do_newfs); safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); } #endif else msg = MSG_NOT_APPLICABLE; break; case 'U': clear(); if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written out your changes -\n" "it's too late to undo!"); } else if (!msgNoYes("Are you SURE you want to Undo everything?")) { variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); for (i = 0; devs[i]; i++) { Disk *d; if (!devs[i]->enabled) continue; else if ((d = Open_Disk(devs[i]->name)) != NULL) { Free_Disk(devs[i]->private); devs[i]->private = d; #ifdef WITH_SLICES diskPartition(devs[i]); #endif } } record_label_chunks(devs, dev); } clear_wins(); break; case 'W': if (!variable_cmp(DISK_LABELLED, "written")) { msgConfirm("You've already written out your changes - if you\n" "wish to overwrite them, you'll have to restart\n" "sysinstall first."); } else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_LABELLED, "yes", 0); diskLabelCommit(NULL); } clear_wins(); break; case 'Z': /* Set newfs command line */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) getNewfsCmd(label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; #ifndef __ia64__ case '|': if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" "This is an entirely undocumented feature which you are not\n" "expected to understand!")) { int i; Device **devs; dialog_clear(); end_dialog(); DialogActive = FALSE; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Can't find any disk devices!"); break; } for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { if (devs[i]->enabled) slice_wizard(((Disk *)devs[i]->private)); } if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); DialogActive = TRUE; record_label_chunks(devs, dev); clear_wins(); } else msg = "A most prudent choice!"; break; #endif case '\033': /* ESC */ case 'Q': labeling = FALSE; break; default: beep(); sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); msg = _msg; break; } if (label_chunk_info[here].type == PART_SLICE) pslice_focus = here; else label_focus = here; } restorescr(w); return DITEM_SUCCESS; } -static __inline int -requested_part_size(char *varName, int nom, int def, int perc) +static __inline daddr_t +requested_part_size(char *varName, daddr_t nom, int def, int perc) { char *cp; - int sz; + daddr_t sz; if ((cp = variable_get(varName)) != NULL) - sz = atoi(cp); + sz = strtoimax(cp, NULL, 0); else sz = nom + (def - nom) * perc / 100; return(sz * ONE_MEG); } /* * Attempt to auto-label the disk. 'perc' (0-100) scales * the size of the various partitions within appropriate * bounds (NOMINAL through DEFAULT sizes). The procedure * succeeds of NULL is returned. A non-null return message * is either a failure-status message (*req == 0), or * a confirmation requestor (*req == 1). *req is 0 on * entry to this call. * * We autolabel the following partitions: /, swap, /var, /tmp, /usr, * and /home. /home receives any extra left over disk space. */ static char * try_auto_label(Device **devs, Device *dev, int perc, int *req) { - int sz; + daddr_t sz; struct chunk *root_chunk = NULL; struct chunk *swap_chunk = NULL; struct chunk *usr_chunk = NULL; struct chunk *var_chunk = NULL; struct chunk *tmp_chunk = NULL; struct chunk *home_chunk = NULL; int mib[2]; unsigned long physmem; size_t size; Chunk *rootdev, *swapdev, *usrdev, *vardev; Chunk *tmpdev, *homedev; char *msg = NULL; sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) return("Not enough free space to create a new partition in the slice"); (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev, &tmpdev, &homedev); if (!rootdev) { sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); if (!root_chunk) { *req = 1; msg = "Unable to create the root partition. Too big?"; goto done; } root_chunk->private_data = new_part("/", TRUE); root_chunk->private_free = safe_free; root_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!swapdev) { sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); if (sz == 0) { - int nom; - int def; + daddr_t nom; + daddr_t def; mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); def = 2 * (int)(physmem / 512); if (def < SWAP_MIN_SIZE * ONE_MEG) def = SWAP_MIN_SIZE * ONE_MEG; if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; nom = (int)(physmem / 512) / 8; sz = nom + (def - nom) * perc / 100; } swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_SWAP, CHUNK_AUTO_SIZE); if (!swap_chunk) { *req = 1; msg = "Unable to create the swap partition. Too big?"; goto done; } swap_chunk->private_data = 0; swap_chunk->private_free = safe_free; record_label_chunks(devs, dev); } if (!vardev) { sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc); var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!var_chunk) { *req = 1; msg = "Not enough free space for /var - you will need to\n" "partition your disk manually with a custom install!"; goto done; } var_chunk->private_data = new_part("/var", TRUE); var_chunk->private_free = safe_free; var_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!tmpdev && !variable_get(VAR_NO_TMP)) { sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!tmp_chunk) { *req = 1; msg = "Not enough free space for /tmp - you will need to\n" "partition your disk manually with a custom install!"; goto done; } tmp_chunk->private_data = new_part("/tmp", TRUE); tmp_chunk->private_free = safe_free; tmp_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } if (!usrdev && !variable_get(VAR_NO_USR)) { sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); #if AUTO_HOME == 0 sz = space_free(label_chunk_info[here].c); #endif if (sz) { if (sz < (USR_MIN_SIZE * ONE_MEG)) { *req = 1; msg = "Not enough free space for /usr - you will need to\n" "partition your disk manually with a custom install!"; } usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!usr_chunk) { msg = "Unable to create the /usr partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"; goto done; } usr_chunk->private_data = new_part("/usr", TRUE); usr_chunk->private_free = safe_free; usr_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } } #if AUTO_HOME == 1 if (!homedev && !variable_get(VAR_NO_HOME)) { sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); if (sz < space_free(label_chunk_info[here].c)) sz = space_free(label_chunk_info[here].c); if (sz) { if (sz < (HOME_MIN_SIZE * ONE_MEG)) { *req = 1; msg = "Not enough free space for /home - you will need to\n" "partition your disk manually with a custom install!"; goto done; } home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, CHUNK_AUTO_SIZE); if (!home_chunk) { msg = "Unable to create the /home partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"; goto done; } home_chunk->private_data = new_part("/home", TRUE); home_chunk->private_free = safe_free; home_chunk->flags |= CHUNK_NEWFS; record_label_chunks(devs, dev); } } #endif /* At this point, we're reasonably "labelled" */ if (variable_cmp(DISK_LABELLED, "written")) variable_set2(DISK_LABELLED, "yes", 0); done: if (msg) { if (root_chunk) Delete_Chunk(root_chunk->disk, root_chunk); if (swap_chunk) Delete_Chunk(swap_chunk->disk, swap_chunk); if (var_chunk) Delete_Chunk(var_chunk->disk, var_chunk); if (tmp_chunk) Delete_Chunk(tmp_chunk->disk, tmp_chunk); if (usr_chunk) Delete_Chunk(usr_chunk->disk, usr_chunk); if (home_chunk) Delete_Chunk(home_chunk->disk, home_chunk); record_label_chunks(devs, dev); } return(msg); } static int diskLabelNonInteractive(Device *dev) { char *cp; PartType type; PartInfo *p; u_long flags; int i, status; Device **devs; Disk *d; status = DITEM_SUCCESS; cp = variable_get(VAR_DISK); if (!cp) { msgConfirm("diskLabel: No disk selected - can't label automatically."); return DITEM_FAILURE; } devs = deviceFind(cp, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("diskLabel: No disk device %s found!", cp); return DITEM_FAILURE; } if (dev) d = dev->private; else d = devs[0]->private; record_label_chunks(devs, dev); for (i = 0; label_chunk_info[i].c; i++) { Chunk *c1 = label_chunk_info[i].c; if (label_chunk_info[i].type == PART_SLICE) { char name[512]; char typ[10], mpoint[50]; int entries; for (entries = 1;; entries++) { - int sz, soft = 0; + intmax_t sz; + int soft = 0; snprintf(name, sizeof name, "%s-%d", c1->name, entries); if ((cp = variable_get(name)) == NULL) break; - if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) { + if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; break; } else { Chunk *tmp; flags = 0; if (!strcmp(typ, "swap")) { type = PART_SWAP; strcpy(mpoint, "SWAP"); } else { type = PART_FILESYSTEM; if (!strcmp(mpoint, "/")) flags |= CHUNK_IS_ROOT; } if (!sz) sz = space_free(c1); if (sz > space_free(c1)) { msgConfirm("Not enough free space to create partition: %s", mpoint); status = DITEM_FAILURE; break; } if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { msgConfirm("Unable to create from partition spec: %s. Too big?", cp); status = DITEM_FAILURE; break; } else { PartInfo *pi; pi = tmp->private_data = new_part(mpoint, TRUE); tmp->private_free = safe_free; pi->newfs_data.newfs_ufs.softupdates = soft; } } } } else { /* Must be something we can set a mountpoint for */ cp = variable_get(c1->name); if (cp) { char mpoint[50], do_newfs[8]; Boolean newfs = FALSE; do_newfs[0] = '\0'; if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; break; } newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; if (c1->private_data) { p = c1->private_data; p->do_newfs = newfs; strcpy(p->mountpoint, mpoint); } else { c1->private_data = new_part(mpoint, newfs); c1->private_free = safe_free; } if (!strcmp(mpoint, "/")) c1->flags |= CHUNK_IS_ROOT; else c1->flags &= ~CHUNK_IS_ROOT; } } } if (status == DITEM_SUCCESS) variable_set2(DISK_LABELLED, "yes", 0); return status; }