svhlabel.c revision 1.3 1 /* $NetBSD: svhlabel.c,v 1.3 2007/06/30 00:54:09 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.3 2007/06/30 00:54:09 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 <fs/efs/efs_sb.h>
57
58 #include "dkcksum.h"
59 #include "extern.h"
60
61 int main(int, char **);
62 static void usage(void);
63 static void getlabel(int);
64 static void setlabel(int, int);
65 static int getparts(int, int);
66 static int is_efs(int, uint32_t);
67 static struct sgi_boot_block *convert_sgi_boot_block(unsigned char *);
68
69 struct disklabel label;
70
71 static void
72 getlabel(int sd)
73 {
74
75 if (ioctl(sd, DIOCGDINFO, &label) < 0) {
76 perror("get label");
77 exit(1);
78 }
79 /*
80 * Some ports seem to not set the number of partitions
81 * correctly, albeit they seem to set the raw partition ok!
82 */
83 if (label.d_npartitions <= getrawpartition())
84 label.d_npartitions = getrawpartition() + 1;
85 }
86
87 static void
88 setlabel(int sd, int doraw)
89 {
90 int one = 1;
91
92 label.d_checksum = 0;
93 label.d_checksum = dkcksum(&label);
94 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
95 perror("set label");
96 exit(1);
97 }
98 if (!doraw)
99 /* If we haven't written to the disk, don't discard on close */
100 ioctl(sd, DIOCKLABEL, &one);
101
102 }
103
104 static int
105 getparts(int sd, int verbose)
106 {
107 unsigned char buf[DEV_BSIZE];
108 struct sgi_boot_block *vh;
109 struct partition npe;
110 int i, j, changed;
111
112 changed = 0;
113
114 if (lseek(sd, 0, SEEK_SET) == -1) {
115 perror("seek vh");
116 exit(1);
117 }
118 if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
119 perror("read vh");
120 exit(1);
121 }
122 vh = convert_sgi_boot_block(buf);
123
124 if (vh->magic != SGI_BOOT_BLOCK_MAGIC)
125 return (changed);
126
127 if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE)
128 changed++;
129 label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE;
130
131 for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
132 if (vh->partitions[i].blocks == 0)
133 continue;
134
135 if (j == MAXPARTITIONS)
136 break;
137
138 switch (vh->partitions[i].type) {
139 case SGI_PTYPE_EFS:
140 /*
141 * For some reason, my IRIX CDs list EFS partitions as SYSV!?
142 */
143 case SGI_PTYPE_SYSV:
144 if (is_efs(sd, vh->partitions[i].first)) {
145 npe.p_fstype = FS_EFS;
146 npe.p_size = vh->partitions[i].blocks;
147 npe.p_offset = vh->partitions[i].first;
148 npe.p_fsize = 0;
149 npe.p_frag = 0;
150 npe.p_cpg = 0;
151 }
152 break;
153
154 case SGI_PTYPE_VOLUME:
155 if (label.d_secperunit != vh->partitions[i].blocks)
156 changed++;
157 label.d_secperunit = vh->partitions[i].blocks;
158 continue;
159
160 default:
161 continue;
162 }
163
164 if (j >= label.d_npartitions)
165 break;
166
167 if (j == getrawpartition()) {
168 if (++j >= label.d_npartitions)
169 break;
170 }
171
172 if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) {
173 label.d_partitions[j] = npe;
174 changed++;
175 }
176
177 j++;
178 }
179
180 /* XXX - fudge */
181 if (label.d_nsectors != 1 || label.d_ntracks != 1 ||
182 label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit)
183 changed++;
184 label.d_nsectors = 1;
185 label.d_ntracks = 1;
186 label.d_secpercyl = 1;
187 label.d_ncylinders = label.d_secperunit;
188
189
190 i = getrawpartition();
191 if (label.d_partitions[i].p_fstype != FS_UNUSED ||
192 label.d_partitions[i].p_offset != 0 ||
193 label.d_partitions[i].p_size != label.d_secperunit) {
194 label.d_partitions[i].p_fstype = FS_UNUSED;
195 label.d_partitions[i].p_offset = 0;
196 label.d_partitions[i].p_size = label.d_secperunit;
197 changed++;
198 }
199
200 return (changed);
201 }
202
203 static int
204 is_efs(int sd, uint32_t blkoff)
205 {
206 off_t oldoff;
207 uint32_t magic;
208
209 if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) {
210 perror("is_efs lseek 0");
211 exit(1);
212 }
213
214 /* EFS superblock begins at block offset 1 */
215 blkoff++;
216
217 if (lseek(sd, (blkoff*SGI_BOOT_BLOCK_BLOCKSIZE) + 28, SEEK_SET) == -1) {
218 perror("is_efs lseek 1");
219 exit(1);
220 }
221
222 if (read(sd, &magic, sizeof(magic)) != 4) {
223 perror("is_efs read");
224 exit(1);
225 }
226
227 if (lseek(sd, oldoff, SEEK_SET) == -1) {
228 perror("is_efs lseek 2");
229 exit(1);
230 }
231
232 BE32TOH(magic);
233
234 return (magic == EFS_SB_MAGIC || magic == EFS_SB_NEWMAGIC);
235 }
236
237 static struct sgi_boot_block *
238 convert_sgi_boot_block(unsigned char *buf)
239 {
240 struct sgi_boot_block *vh;
241 int i;
242
243 vh = (struct sgi_boot_block *)buf;
244
245 BE32TOH(vh->magic);
246 BE16TOH(vh->root);
247 BE16TOH(vh->swap);
248
249 BE16TOH(vh->dp.dp_cyls);
250 BE16TOH(vh->dp.dp_shd0);
251 BE16TOH(vh->dp.dp_trks0);
252 BE16TOH(vh->dp.dp_secs);
253 BE16TOH(vh->dp.dp_secbytes);
254 BE16TOH(vh->dp.dp_interleave);
255 BE32TOH(vh->dp.dp_flags);
256 BE32TOH(vh->dp.dp_datarate);
257 BE32TOH(vh->dp.dp_nretries);
258 BE32TOH(vh->dp.dp_mspw);
259 BE16TOH(vh->dp.dp_xgap1);
260 BE16TOH(vh->dp.dp_xsync);
261 BE16TOH(vh->dp.dp_xrdly);
262 BE16TOH(vh->dp.dp_xgap2);
263 BE16TOH(vh->dp.dp_xrgate);
264 BE16TOH(vh->dp.dp_xwcont);
265
266 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
267 BE32TOH(vh->voldir[i].block);
268 BE32TOH(vh->voldir[i].bytes);
269 }
270
271 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
272 BE32TOH(vh->partitions[i].blocks);
273 BE32TOH(vh->partitions[i].first);
274 BE32TOH(vh->partitions[i].type);
275 }
276
277 BE32TOH(vh->checksum);
278
279 return (vh);
280 }
281
282 static void
283 usage(void)
284 {
285 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
286 getprogname());
287 exit(1);
288 }
289
290
291 int
292 main(int argc, char **argv)
293 {
294 int sd, ch, changed;
295 char name[MAXPATHLEN];
296 int force; /* force label update */
297 int raw; /* update on-disk label as well */
298 int verbose; /* verbose output */
299 int write_it; /* update in-core label if changed */
300
301 force = 0;
302 raw = 0;
303 verbose = 1;
304 write_it = 0;
305 while ((ch = getopt(argc, argv, "fqrw")) != -1) {
306 switch (ch) {
307 case 'f':
308 force = 1;
309 break;
310 case 'q':
311 verbose = 0;
312 break;
313 case 'r':
314 raw = 1;
315 break;
316 case 'w':
317 write_it = 1;
318 break;
319 default:
320 usage();
321 }
322 }
323 argc -= optind;
324 argv += optind;
325 if (argc != 1)
326 usage();
327
328 if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
329 (size_t)MAXPATHLEN, 1)) < 0) {
330 perror(argv[0]);
331 exit(1);
332 }
333 getlabel(sd);
334 changed = getparts(sd, verbose);
335
336 if (verbose) {
337 putchar('\n');
338 showpartitions(stdout, &label, 0);
339 putchar('\n');
340 }
341 if (write_it) {
342 if (! changed && ! force)
343 printf("No change; not updating disk label.\n");
344 else {
345 if (verbose)
346 printf("Updating in-core %sdisk label.\n",
347 raw ? "and on-disk " : "");
348 raw = 0; /* XXX */
349 setlabel(sd, raw);
350 }
351 } else {
352 printf("Not updating disk label.\n");
353 }
354 close(sd);
355 return (0);
356 }
357