1 /* $NetBSD: svhlabel.c,v 1.7 2013/02/07 10:44:45 apb 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.7 2013/02/07 10:44:45 apb 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.h>
57 #include <fs/efs/efs_sb.h>
58
59 #include "dkcksum.h"
60 #include "extern.h"
61
62 __dead 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 static int rawpart;
71
72 static void
getlabel(int sd)73 getlabel(int sd)
74 {
75
76 if (ioctl(sd, DIOCGDINFO, &label) < 0) {
77 perror("get label");
78 exit(1);
79 }
80 /*
81 * Some ports seem to not set the number of partitions
82 * correctly, albeit they seem to set the raw partition ok!
83 */
84 if (label.d_npartitions <= rawpart)
85 label.d_npartitions = rawpart + 1;
86 }
87
88 static void
setlabel(int sd,int doraw)89 setlabel(int sd, int doraw)
90 {
91 int one = 1;
92
93 label.d_checksum = 0;
94 label.d_checksum = dkcksum(&label);
95 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
96 perror("set label");
97 exit(1);
98 }
99 if (!doraw)
100 /* If we haven't written to the disk, don't discard on close */
101 ioctl(sd, DIOCKLABEL, &one);
102
103 }
104
105 static int
getparts(int sd,int verbose)106 getparts(int sd, int verbose)
107 {
108 unsigned char buf[DEV_BSIZE];
109 struct sgi_boot_block *vh;
110 struct partition npe;
111 int i, j, changed;
112
113 changed = 0;
114
115 if (lseek(sd, 0, SEEK_SET) == -1) {
116 perror("seek vh");
117 exit(1);
118 }
119 if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
120 perror("read vh");
121 exit(1);
122 }
123 vh = convert_sgi_boot_block(buf);
124
125 if (vh->magic != SGI_BOOT_BLOCK_MAGIC)
126 return (changed);
127
128 if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE)
129 changed++;
130 label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE;
131
132 for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
133 if (vh->partitions[i].blocks == 0)
134 continue;
135
136 if (j == MAXPARTITIONS)
137 break;
138
139 switch (vh->partitions[i].type) {
140 case SGI_PTYPE_EFS:
141 /*
142 * For some reason, my IRIX CDs list EFS partitions as SYSV!?
143 */
144 case SGI_PTYPE_SYSV:
145 if (is_efs(sd, vh->partitions[i].first)) {
146 npe.p_fstype = FS_EFS;
147 npe.p_size = vh->partitions[i].blocks;
148 npe.p_offset = vh->partitions[i].first;
149 npe.p_fsize = 0;
150 npe.p_frag = 0;
151 npe.p_cpg = 0;
152 }
153 break;
154
155 case SGI_PTYPE_VOLUME:
156 if (label.d_secperunit != (uint32_t)vh->partitions[i].blocks)
157 changed++;
158 label.d_secperunit = vh->partitions[i].blocks;
159 continue;
160
161 default:
162 continue;
163 }
164
165 if (j >= label.d_npartitions)
166 break;
167
168 if (j == rawpart) {
169 if (++j >= label.d_npartitions)
170 break;
171 }
172
173 if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) {
174 label.d_partitions[j] = npe;
175 changed++;
176 }
177
178 j++;
179 }
180
181 /* XXX - fudge */
182 if (label.d_nsectors != 1 || label.d_ntracks != 1 ||
183 label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit)
184 changed++;
185 label.d_nsectors = 1;
186 label.d_ntracks = 1;
187 label.d_secpercyl = 1;
188 label.d_ncylinders = label.d_secperunit;
189
190 i = rawpart;
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
is_efs(int sd,uint32_t blkoff)204 is_efs(int sd, uint32_t blkoff)
205 {
206 struct efs_sb sb;
207 off_t oldoff;
208
209 if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) {
210 perror("is_efs lseek 0");
211 exit(1);
212 }
213
214 blkoff *= SGI_BOOT_BLOCK_BLOCKSIZE;
215 if (lseek(sd, blkoff + (EFS_BB_SB * EFS_BB_SIZE), SEEK_SET) == -1) {
216 perror("is_efs lseek 1");
217 exit(1);
218 }
219
220 if (read(sd, &sb, sizeof(sb)) != sizeof(sb)) {
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(sb.sb_magic);
231
232 return (sb.sb_magic == EFS_SB_MAGIC || sb.sb_magic == EFS_SB_NEWMAGIC);
233 }
234
235 static struct sgi_boot_block *
convert_sgi_boot_block(unsigned char * buf)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
usage(void)281 usage(void)
282 {
283 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
284 getprogname());
285 exit(1);
286 }
287
288
289 int
main(int argc,char ** argv)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 rawpart = getrawpartition();
327 if (rawpart < 0)
328 err(EXIT_FAILURE, "getrawpartition");
329
330 if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
331 (size_t)MAXPATHLEN, 1)) < 0) {
332 perror(argv[0]);
333 exit(1);
334 }
335 getlabel(sd);
336 changed = getparts(sd, verbose);
337
338 if (verbose) {
339 putchar('\n');
340 showpartitions(stdout, &label, 0);
341 putchar('\n');
342 }
343 if (write_it) {
344 if (! changed && ! force)
345 printf("No change; not updating disk label.\n");
346 else {
347 if (verbose)
348 printf("Updating in-core %sdisk label.\n",
349 raw ? "and on-disk " : "");
350 raw = 0; /* XXX */
351 setlabel(sd, raw);
352 }
353 } else {
354 printf("Not updating disk label.\n");
355 }
356 close(sd);
357 return (0);
358 }
359