123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * prep - prepare plan9 disk partition
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <disk.h>
- #include "edit.h"
- enum {
- Maxpath = 128,
- };
- static int blank;
- static int file;
- static int doautox;
- static int printflag;
- static Part **opart;
- static int nopart;
- static char *osecbuf;
- static char *secbuf;
- static int rdonly;
- static int dowrite;
- static int docache;
- static int donvram;
- static void autoxpart(Edit*);
- static Part *mkpart(char*, int64_t, int64_t, int);
- static void rdpart(Edit*);
- static void wrpart(Edit*);
- static void checkfat(Disk*);
- static void cmdsum(Edit*, Part*, int64_t, int64_t);
- static char *cmdadd(Edit*, char*, int64_t, int64_t);
- static char *cmddel(Edit*, Part*);
- static char *cmdokname(Edit*, char*);
- static char *cmdwrite(Edit*);
- Edit edit = {
- .add= cmdadd,
- .del= cmddel,
- .okname=cmdokname,
- .sum= cmdsum,
- .write= cmdwrite,
- .unit= "sector",
- };
- typedef struct Auto Auto;
- struct Auto
- {
- char *name;
- uint64_t min;
- uint64_t max;
- uint weight;
- uint8_t alloc;
- uint64_t size;
- };
- #define TB (1024LL*GB)
- #define GB (1024*1024*1024)
- #define MB (1024*1024)
- #define KB (1024)
- /*
- * Order matters -- this is the layout order on disk.
- */
- Auto autox[] =
- {
- { "9fat", 10*MB, 100*MB, 10, },
- { "nvram", 512, 512, 1, },
- { "fscfg", 1024, 8192, 1, },
- { "fs", 200*MB, 0, 10, },
- { "fossil", 200*MB, 0, 4, },
- { "arenas", 500*MB, 0, 20, },
- { "isect", 25*MB, 0, 1, },
- { "bloom", 4*MB, 512*MB, 1, },
- { "other", 200*MB, 0, 4, },
- { "swap", 100*MB, 512*MB, 1, },
- { "cache", 50*MB, 1*GB, 2, },
- };
- void
- usage(void)
- {
- fprint(2, "usage: disk/prep [-bcfprw] [-a partname]... [-s sectorsize] /dev/sdC0/plan9\n");
- exits("usage");
- }
- void
- main(int argc, char **argv)
- {
- int i;
- char *p;
- Disk *disk;
- int64_t secsize;
- secsize = 0;
- ARGBEGIN{
- case 'a':
- p = EARGF(usage());
- for(i=0; i<nelem(autox); i++){
- if(strcmp(p, autox[i].name) == 0){
- if(autox[i].alloc){
- fprint(2, "you said -a %s more than once.\n", p);
- usage();
- }
- autox[i].alloc = 1;
- break;
- }
- }
- if(i == nelem(autox)){
- fprint(2, "don't know how to create automatic partition %s\n", p);
- usage();
- }
- doautox = 1;
- break;
- case 'b':
- blank++;
- break;
- case 'c':
- docache++;
- break;
- case 'f':
- file++;
- break;
- case 'n':
- donvram++;
- break;
- case 'p':
- printflag++;
- rdonly++;
- break;
- case 'r':
- rdonly++;
- break;
- case 's':
- secsize = atoi(ARGF());
- break;
- case 'w':
- dowrite++;
- break;
- default:
- usage();
- }ARGEND;
- if(argc != 1)
- usage();
- disk = opendisk(argv[0], rdonly, file);
- if(disk == nil)
- sysfatal("cannot open disk: %r");
- if(secsize != 0) {
- disk->secsize = secsize;
- disk->secs = disk->size / secsize;
- }
- edit.end = disk->secs;
- checkfat(disk);
- secbuf = emalloc(disk->secsize+1);
- osecbuf = emalloc(disk->secsize+1);
- edit.disk = disk;
- if(blank == 0)
- rdpart(&edit);
- opart = emalloc(edit.npart*sizeof(opart[0]));
- /* save old partition table */
- for(i=0; i<edit.npart; i++)
- opart[i] = edit.part[i];
- nopart = edit.npart;
- if(printflag) {
- runcmd(&edit, (char[]){"P"});
- exits(0);
- }
- if(doautox)
- autoxpart(&edit);
- if(dowrite) {
- runcmd(&edit, (char[]){"w"});
- exits(0);
- }
- runcmd(&edit, (char[]){"p"});
- for(;;) {
- fprint(2, ">>> ");
- runcmd(&edit, getline(&edit));
- }
- }
- static void
- cmdsum(Edit *edit, Part *p, int64_t a, int64_t b)
- {
- int64_t sz, div;
- char *suf, *name;
- char c;
- c = p && p->changed ? '\'' : ' ';
- name = p ? p->name : "empty";
- sz = (b-a)*edit->disk->secsize;
- if(sz >= 1*TB){
- suf = "TB";
- div = TB;
- }else if(sz >= 1*GB){
- suf = "GB";
- div = GB;
- }else if(sz >= 1*MB){
- suf = "MB";
- div = MB;
- }else if(sz >= 1*KB){
- suf = "KB";
- div = KB;
- }else{
- if (sz < 0)
- fprint(2, "%s: negative size!\n", argv0);
- suf = "B ";
- div = 1;
- }
- if(div == 1)
- print("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,
- edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);
- else
- print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,
- edit->disk->width, a, edit->disk->width, b, b-a,
- sz/div, (int)(((sz%div)*100)/div), suf);
- }
- static char*
- cmdadd(Edit *edit, char *name, int64_t start, int64_t end)
- {
- if(start < 2 && strcmp(name, "9fat") != 0)
- return "overlaps with the pbs and/or the partition table";
- return addpart(edit, mkpart(name, start, end, 1));
- }
- static char*
- cmddel(Edit *edit, Part *p)
- {
- return delpart(edit, p);
- }
- static char*
- cmdwrite(Edit *edit)
- {
- wrpart(edit);
- return nil;
- }
- static char isfrog[256]={
- /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
- /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
- /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
- /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
- [' '] 1,
- ['/'] 1,
- [0x7f] 1,
- };
- static char*
- cmdokname(Edit *e, char *elem)
- {
- for(; *elem; elem++)
- if(isfrog[*(uint8_t*)elem])
- return "bad character in name";
- return nil;
- }
- static Part*
- mkpart(char *name, int64_t start, int64_t end, int changed)
- {
- Part *p;
- p = emalloc(sizeof(*p));
- p->name = estrdup(name);
- p->ctlname = estrdup(name);
- p->start = start;
- p->end = end;
- p->changed = changed;
- return p;
- }
- /* plan9 partition is first sector of the disk */
- static void
- rdpart(Edit *edit)
- {
- int i, nline, nf, waserr;
- int64_t a, b;
- char *line[128];
- char *f[5];
- char *err;
- Disk *disk;
- disk = edit->disk;
- seek(disk->fd, disk->secsize, 0);
- if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)
- return;
- osecbuf[disk->secsize] = '\0';
- memmove(secbuf, osecbuf, disk->secsize+1);
- if(strncmp(secbuf, "part", 4) != 0){
- fprint(2, "no plan9 partition table found\n");
- return;
- }
- waserr = 0;
- nline = getfields(secbuf, line, nelem(line), 1, "\n");
- for(i=0; i<nline; i++){
- if(strncmp(line[i], "part", 4) != 0) {
- Error:
- if(waserr == 0)
- fprint(2, "syntax error reading partition\n");
- waserr = 1;
- continue;
- }
- nf = getfields(line[i], f, nelem(f), 1, " \t\r");
- if(nf != 4 || strcmp(f[0], "part") != 0)
- goto Error;
- a = strtoll(f[2], 0, 0);
- b = strtoll(f[3], 0, 0);
- if(a >= b)
- goto Error;
- if(err = addpart(edit, mkpart(f[1], a, b, 0))) {
- fprint(2, "?%s: not continuing\n", err);
- exits("partition");
- }
- }
- }
- static void
- autoxpart(Edit *edit)
- {
- int i, totw, futz;
- int64_t secs, secsize, s;
- char *err;
- if(edit->npart > 0) {
- if(doautox)
- fprint(2, "partitions already exist; not repartitioning\n");
- return;
- }
- secs = edit->disk->secs;
- secsize = edit->disk->secsize;
- for(;;){
- /* compute total weights */
- totw = 0;
- for(i=0; i<nelem(autox); i++){
- if(autox[i].alloc==0 || autox[i].size)
- continue;
- totw += autox[i].weight;
- }
- if(totw == 0)
- break;
- if(secs <= 0){
- fprint(2, "ran out of disk space during autoxpartition.\n");
- return;
- }
- /* assign any minimums for small disks */
- futz = 0;
- for(i=0; i<nelem(autox); i++){
- if(autox[i].alloc==0 || autox[i].size)
- continue;
- s = (secs*autox[i].weight)/totw;
- if(s < autox[i].min/secsize){
- autox[i].size = autox[i].min/secsize;
- secs -= autox[i].size;
- futz = 1;
- break;
- }
- }
- if(futz)
- continue;
- /* assign any maximums for big disks */
- futz = 0;
- for(i=0; i<nelem(autox); i++){
- if(autox[i].alloc==0 || autox[i].size)
- continue;
- s = (secs*autox[i].weight)/totw;
- if(autox[i].max && s > autox[i].max/secsize){
- autox[i].size = autox[i].max/secsize;
- secs -= autox[i].size;
- futz = 1;
- break;
- }
- }
- if(futz)
- continue;
- /* finally, assign partition sizes according to weights */
- for(i=0; i<nelem(autox); i++){
- if(autox[i].alloc==0 || autox[i].size)
- continue;
- s = (secs*autox[i].weight)/totw;
- autox[i].size = s;
- /* use entire disk even in face of rounding errors */
- secs -= autox[i].size;
- totw -= autox[i].weight;
- }
- }
- for(i=0; i<nelem(autox); i++)
- if(autox[i].alloc)
- print("%s %llud\n", autox[i].name, autox[i].size);
- s = 0;
- for(i=0; i<nelem(autox); i++){
- if(autox[i].alloc == 0)
- continue;
- if(err = addpart(edit, mkpart(autox[i].name, s, s+autox[i].size, 1)))
- fprint(2, "addpart %s: %s\n", autox[i].name, err);
- s += autox[i].size;
- }
- }
- static void
- restore(Edit *edit, int ctlfd)
- {
- int i;
- int64_t offset;
- offset = edit->disk->offset;
- fprint(2, "attempting to restore partitions to previous state\n");
- if(seek(edit->disk->wfd, edit->disk->secsize, 0) != 0){
- fprint(2, "cannot restore: error seeking on disk\n");
- exits("inconsistent");
- }
- if(write(edit->disk->wfd, osecbuf, edit->disk->secsize) != edit->disk->secsize){
- fprint(2, "cannot restore: couldn't write old partition table to disk\n");
- exits("inconsistent");
- }
- if(ctlfd >= 0){
- for(i=0; i<edit->npart; i++)
- fprint(ctlfd, "delpart %s", edit->part[i]->name);
- for(i=0; i<nopart; i++){
- if(fprint(ctlfd, "part %s %lld %lld", opart[i]->name, opart[i]->start+offset, opart[i]->end+offset) < 0){
- fprint(2, "restored disk partition table but not kernel; reboot\n");
- exits("inconsistent");
- }
- }
- }
- exits("restored");
- }
- static void
- wrpart(Edit *edit)
- {
- int i, n;
- Disk *disk;
- disk = edit->disk;
- memset(secbuf, 0, disk->secsize);
- n = 0;
- for(i=0; i<edit->npart; i++)
- n += snprint(secbuf+n, disk->secsize-n, "part %s %lld %lld\n",
- edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
- if(seek(disk->wfd, disk->secsize, 0) != disk->secsize){
- fprint(2, "error seeking %d %lld on disk: %r\n", disk->wfd, disk->secsize);
- exits("seek");
- }
- if(write(disk->wfd, secbuf, disk->secsize) != disk->secsize){
- fprint(2, "error writing partition table to disk\n");
- restore(edit, -1);
- }
- if(ctldiff(edit, disk->ctlfd) < 0)
- fprint(2, "?warning: partitions could not be updated in devsd\n");
- }
- /*
- * Look for a boot sector in sector 1, as would be
- * the case if editing /dev/sdC0/data when that
- * was really a bootable disk.
- */
- static void
- checkfat(Disk *disk)
- {
- uint8_t buf[32];
- if(seek(disk->fd, disk->secsize, 0) < 0
- || read(disk->fd, buf, sizeof(buf)) < sizeof(buf))
- return;
- if(buf[0] != 0xEB || buf[1] != 0x3C || buf[2] != 0x90)
- return;
- fprint(2,
- "there's a fat partition where the\n"
- "plan9 partition table would go.\n"
- "if you really want to overwrite it, zero\n"
- "the second sector of the disk and try again\n");
- exits("fat partition");
- }
|