svhlabel.c revision 1.1 1 /* $NetBSD: svhlabel.c,v 1.1 2007/06/29 23:30:25 rumble Exp $ */
2
3 /*
4 * Copyright (C) 2007 Stephen M. Rumble.
5 * Copyright (C) 1998 Wolfgang Solfrank.
6 * Copyright (C) 1998 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __RCSID("$NetBSD: svhlabel.c,v 1.1 2007/06/29 23:30:25 rumble Exp $");
38 #endif /* not lint */
39
40 #include <stdio.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <limits.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <util.h>
49
50 #include <sys/param.h>
51 #define FSTYPENAMES
52 #include <sys/disklabel.h>
53 #include <sys/bootblock.h>
54 #include <sys/ioctl.h>
55
56 #include "dkcksum.h"
57 #include "extern.h"
58
59 int main(int, char **);
60 static void usage(void);
61 static void getlabel(int);
62 static void setlabel(int, int);
63 static int getparts(int, int);
64 static int is_efs(int, uint32_t);
65 static struct sgi_boot_block *convert_sgi_boot_block(unsigned char *);
66
67 struct disklabel label;
68
69 static void
70 getlabel(int sd)
71 {
72
73 if (ioctl(sd, DIOCGDINFO, &label) < 0) {
74 perror("get label");
75 exit(1);
76 }
77 /*
78 * Some ports seem to not set the number of partitions
79 * correctly, albeit they seem to set the raw partition ok!
80 */
81 if (label.d_npartitions <= getrawpartition())
82 label.d_npartitions = getrawpartition() + 1;
83 }
84
85 static void
86 setlabel(int sd, int doraw)
87 {
88 int one = 1;
89
90 label.d_checksum = 0;
91 label.d_checksum = dkcksum(&label);
92 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
93 perror("set label");
94 exit(1);
95 }
96 if (!doraw)
97 /* If we haven't written to the disk, don't discard on close */
98 ioctl(sd, DIOCKLABEL, &one);
99
100 }
101
102 static int
103 getparts(int sd, int verbose)
104 {
105 unsigned char buf[DEV_BSIZE];
106 struct sgi_boot_block *vh;
107 struct partition npe;
108 int i, j, changed;
109
110 changed = 0;
111
112 if (lseek(sd, 0, SEEK_SET) == -1) {
113 perror("seek vh");
114 exit(1);
115 }
116 if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
117 perror("read vh");
118 exit(1);
119 }
120 vh = convert_sgi_boot_block(buf);
121
122 if (vh->magic != SGI_BOOT_BLOCK_MAGIC)
123 return (changed);
124
125 if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE)
126 changed++;
127 label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE;
128
129 for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
130 if (vh->partitions[i].blocks == 0)
131 continue;
132
133 if (j == MAXPARTITIONS)
134 break;
135
136 switch (vh->partitions[i].type) {
137 case SGI_PTYPE_EFS:
138 /*
139 * For some reason, my IRIX CDs list EFS partitions as SYSV!?
140 */
141 case SGI_PTYPE_SYSV:
142 if (is_efs(sd, vh->partitions[i].first)) {
143 npe.p_fstype = FS_EFS;
144 npe.p_size = vh->partitions[i].blocks;
145 npe.p_offset = vh->partitions[i].first;
146 npe.p_fsize = 0;
147 npe.p_frag = 0;
148 npe.p_cpg = 0;
149 }
150 break;
151
152 case SGI_PTYPE_VOLUME:
153 if (label.d_secperunit != vh->partitions[i].blocks)
154 changed++;
155 label.d_secperunit = vh->partitions[i].blocks;
156 continue;
157
158 default:
159 continue;
160 }
161
162 if (j >= label.d_npartitions)
163 break;
164
165 if (j == getrawpartition()) {
166 if (++j >= label.d_npartitions)
167 break;
168 }
169
170 if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) {
171 label.d_partitions[j] = npe;
172 changed++;
173 }
174
175 j++;
176 }
177
178 /* XXX - fudge */
179 if (label.d_nsectors != 1 || label.d_ntracks != 1 ||
180 label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit)
181 changed++;
182 label.d_nsectors = 1;
183 label.d_ntracks = 1;
184 label.d_secpercyl = 1;
185 label.d_ncylinders = label.d_secperunit;
186
187
188 i = getrawpartition();
189 if (label.d_partitions[i].p_fstype != FS_UNUSED ||
190 label.d_partitions[i].p_offset != 0 ||
191 label.d_partitions[i].p_size != label.d_secperunit) {
192 label.d_partitions[i].p_fstype = FS_UNUSED;
193 label.d_partitions[i].p_offset = 0;
194 label.d_partitions[i].p_size = label.d_secperunit;
195 changed++;
196 }
197
198 return (changed);
199 }
200
201 static int
202 is_efs(int sd, uint32_t blkoff)
203 {
204 off_t oldoff;
205 uint32_t magic;
206
207 if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) {
208 perror("is_efs lseek 0");
209 exit(1);
210 }
211
212 /* EFS superblock begins at block offset 1 */
213 blkoff++;
214
215 if (lseek(sd, (blkoff*SGI_BOOT_BLOCK_BLOCKSIZE) + 28, SEEK_SET) == -1) {
216 perror("is_efs lseek 1");
217 exit(1);
218 }
219
220 if (read(sd, &magic, sizeof(magic)) != 4) {
221 perror("is_efs read");
222 exit(1);
223 }
224
225 if (lseek(sd, oldoff, SEEK_SET) == -1) {
226 perror("is_efs lseek 2");
227 exit(1);
228 }
229
230 BE32TOH(magic);
231
232 return (magic == 0x00072959 || magic == 0x0007295A);
233 }
234
235 static struct sgi_boot_block *
236 convert_sgi_boot_block(unsigned char *buf)
237 {
238 struct sgi_boot_block *vh;
239 int i;
240
241 vh = (struct sgi_boot_block *)buf;
242
243 BE32TOH(vh->magic);
244 BE16TOH(vh->root);
245 BE16TOH(vh->swap);
246
247 BE16TOH(vh->dp.dp_cyls);
248 BE16TOH(vh->dp.dp_shd0);
249 BE16TOH(vh->dp.dp_trks0);
250 BE16TOH(vh->dp.dp_secs);
251 BE16TOH(vh->dp.dp_secbytes);
252 BE16TOH(vh->dp.dp_interleave);
253 BE32TOH(vh->dp.dp_flags);
254 BE32TOH(vh->dp.dp_datarate);
255 BE32TOH(vh->dp.dp_nretries);
256 BE32TOH(vh->dp.dp_mspw);
257 BE16TOH(vh->dp.dp_xgap1);
258 BE16TOH(vh->dp.dp_xsync);
259 BE16TOH(vh->dp.dp_xrdly);
260 BE16TOH(vh->dp.dp_xgap2);
261 BE16TOH(vh->dp.dp_xrgate);
262 BE16TOH(vh->dp.dp_xwcont);
263
264 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
265 BE32TOH(vh->voldir[i].block);
266 BE32TOH(vh->voldir[i].bytes);
267 }
268
269 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
270 BE32TOH(vh->partitions[i].blocks);
271 BE32TOH(vh->partitions[i].first);
272 BE32TOH(vh->partitions[i].type);
273 }
274
275 BE32TOH(vh->checksum);
276
277 return (vh);
278 }
279
280 static void
281 usage(void)
282 {
283 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
284 getprogname());
285 exit(1);
286 }
287
288
289 int
290 main(int argc, char **argv)
291 {
292 int sd, ch, changed;
293 char name[MAXPATHLEN];
294 int force; /* force label update */
295 int raw; /* update on-disk label as well */
296 int verbose; /* verbose output */
297 int write_it; /* update in-core label if changed */
298
299 force = 0;
300 raw = 0;
301 verbose = 1;
302 write_it = 0;
303 while ((ch = getopt(argc, argv, "fqrw")) != -1) {
304 switch (ch) {
305 case 'f':
306 force = 1;
307 break;
308 case 'q':
309 verbose = 0;
310 break;
311 case 'r':
312 raw = 1;
313 break;
314 case 'w':
315 write_it = 1;
316 break;
317 default:
318 usage();
319 }
320 }
321 argc -= optind;
322 argv += optind;
323 if (argc != 1)
324 usage();
325
326 if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
327 (size_t)MAXPATHLEN, 1)) < 0) {
328 perror(argv[0]);
329 exit(1);
330 }
331 getlabel(sd);
332 changed = getparts(sd, verbose);
333
334 if (verbose) {
335 putchar('\n');
336 showpartitions(stdout, &label, 0);
337 putchar('\n');
338 }
339 if (write_it) {
340 if (! changed && ! force)
341 printf("No change; not updating disk label.\n");
342 else {
343 if (verbose)
344 printf("Updating in-core %sdisk label.\n",
345 raw ? "and on-disk " : "");
346 raw = 0; /* XXX */
347 setlabel(sd, raw);
348 }
349 } else {
350 printf("Not updating disk label.\n");
351 }
352 close(sd);
353 return (0);
354 }
355