]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/mbr.c
Add Erik Quanstrom's smart tool for ATA SMART.
[plan9front.git] / sys / src / cmd / disk / mbr.c
1 /*
2  * install new master boot record boot code on PC disk.
3  */
4
5 #include <u.h>
6 #include <libc.h>
7 #include <disk.h>
8
9 typedef struct {
10         uchar   active;                 /* active flag */
11         uchar   starth;                 /* starting head */
12         uchar   starts;                 /* starting sector */
13         uchar   startc;                 /* starting cylinder */
14         uchar   type;                   /* partition type */
15         uchar   endh;                   /* ending head */
16         uchar   ends;                   /* ending sector */
17         uchar   endc;                   /* ending cylinder */
18         uchar   lba[4];                 /* starting LBA */
19         uchar   size[4];                /* size in sectors */
20 } Tentry;
21
22 enum {
23         Toffset = 0x1BE,                /* offset of partition table */
24
25         Type9   = 0x39,
26 };
27
28 /*
29  * Default boot block prints an error message and reboots. 
30  */
31 static int ndefmbr = Toffset;
32 static char defmbr[512] = {
33 [0x000] 0xEB, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
36         0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
37         0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
38         0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
39         0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
40         0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
41         0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
42         0xC3,  'N',  'o',  't',  ' ',  'a',  ' ',  'b',
43          'o',  'o',  't',  'a',  'b',  'l',  'e',  ' ',
44          'd',  'i',  's',  'c',  ' ',  'o',  'r',  ' ',
45          'd',  'i',  's',  'c',  ' ',  'e',  'r',  'r',
46          'o',  'r', '\r', '\n',  'P',  'r',  'e',  's',
47          's',  ' ',  'a',  'l',  'm',  'o',  's',  't',
48          ' ',  'a',  'n',  'y',  ' ',  'k',  'e',  'y',
49          ' ',  't',  'o',  ' ',  'r',  'e',  'b',  'o',
50          'o',  't',  '.',  '.',  '.', 0x00, 0x00, 0x00,
51 };
52
53 void
54 usage(void)
55 {
56         fprint(2, "usage: disk/mbr [-m mbrfile] disk\n");
57         exits("usage");
58 }
59
60 void
61 fatal(char *fmt, ...)
62 {
63         char err[ERRMAX];
64         va_list arg;
65
66         va_start(arg, fmt);
67         vsnprint(err, ERRMAX, fmt, arg);
68         va_end(arg);
69         fprint(2, "mbr: %s\n", err);
70         exits(err);
71 }
72
73 static void
74 putle32(void* v, u32int i)
75 {
76         uchar *p;
77
78         p = v;
79         p[0] = i;
80         p[1] = i>>8;
81         p[2] = i>>16;
82         p[3] = i>>24;
83 }
84
85 static void
86 writechs(Disk *disk, uchar *p, vlong lba)
87 {
88         int c, h, s;
89
90         s = lba % disk->s;
91         h = (lba / disk->s) % disk->h;
92         c = lba / (disk->s * disk->h);
93
94         if(c >= 1024) {
95                 c = 1023;
96                 h = disk->h - 1;
97                 s = disk->s - 1;
98         }
99
100         p[0] = h;
101         p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
102         p[2] = c;
103 }
104
105 static void
106 wrtentry(Disk *disk, Tentry *tp, int type, u32int base, u32int lba, u32int end)
107 {
108         tp->active = 0x80;              /* make this sole partition active */
109         tp->type = type;
110         writechs(disk, &tp->starth, lba);
111         writechs(disk, &tp->endh, end-1);
112         putle32(tp->lba, lba-base);
113         putle32(tp->size, end-lba);
114 }
115
116 void
117 main(int argc, char **argv)
118 {
119         Disk *disk;
120         Tentry *tp;
121         uchar *mbr, *buf;
122         char *mbrfile;
123         ulong secsize;
124         int flag9, sysfd, nmbr;
125
126         flag9 = 0;
127         mbrfile = nil;
128         ARGBEGIN {
129         case '9':
130                 flag9 = 1;
131                 break;
132         case 'm':
133                 mbrfile = EARGF(usage());
134                 break;
135         default:
136                 usage();
137         } ARGEND
138
139         if(argc < 1)
140                 usage();
141
142         disk = opendisk(argv[0], 0, 0);
143         if(disk == nil)
144                 fatal("opendisk %s: %r", argv[0]);
145
146         if(disk->type == Tfloppy)
147                 fatal("will not install mbr on floppy");
148         /*
149          * we need to cope with 4k-byte sectors on some newer disks.
150          * we're only interested in 512 bytes of mbr, so
151          * on 4k disks, rely on /dev/sd to read-modify-write.
152          */
153         secsize = 512;
154         if(disk->secsize != secsize)
155                 fprint(2, "%s: sector size %lld not %ld, should be okay\n",
156                         argv0, disk->secsize, secsize);
157
158         buf = malloc(secsize*(disk->s+1));
159         mbr = malloc(secsize*disk->s);
160         if(buf == nil || mbr == nil)
161                 fatal("out of memory");
162
163         /*
164          * Start with initial sector from disk.
165          */
166         if(seek(disk->fd, 0, 0) < 0)
167                 fatal("seek to boot sector: %r\n");
168         if(read(disk->fd, mbr, secsize) != secsize)
169                 fatal("reading boot sector: %r");
170
171         if(mbrfile == nil){
172                 nmbr = ndefmbr;
173                 memmove(mbr, defmbr, nmbr);
174         } else {
175                 memset(buf, 0, secsize*disk->s);
176                 if((sysfd = open(mbrfile, OREAD)) < 0)
177                         fatal("open %s: %r", mbrfile);
178                 if((nmbr = read(sysfd, buf, secsize*(disk->s+1))) < 0)
179                         fatal("read %s: %r", mbrfile);
180                 if(nmbr > secsize*disk->s)
181                         fatal("master boot record too large %d > %d", nmbr, secsize*disk->s);
182                 if(nmbr < secsize)
183                         nmbr = secsize;
184                 close(sysfd);
185                 memmove(buf+Toffset, mbr+Toffset, secsize-Toffset);
186                 memmove(mbr, buf, nmbr);
187         }
188
189         if(flag9){
190                 tp = (Tentry*)(mbr+Toffset);
191                 memset(tp, 0, secsize-Toffset);
192                 wrtentry(disk, tp, Type9, 0, disk->s, disk->secs);
193         }
194         mbr[secsize-2] = 0x55;
195         mbr[secsize-1] = 0xAA;
196         nmbr = (nmbr+secsize-1)&~(secsize-1);
197         if(seek(disk->wfd, 0, 0) < 0)
198                 fatal("seek to MBR sector: %r\n");
199         if(write(disk->wfd, mbr, nmbr) != nmbr)
200                 fatal("writing MBR: %r");
201         
202         exits(0);
203 }