sunlabel.c revision 1.2 1 1.1 mrg /* This file is in the public domain. */
2 1.1 mrg /*
3 1.1 mrg * Compile-time defines of note:
4 1.1 mrg *
5 1.1 mrg * S_COMMAND
6 1.1 mrg * NO_S_COMMAND
7 1.1 mrg * Provide, or don't provide, the S command, which sets
8 1.1 mrg * the in-core disklabel (as opposed to the on-disk
9 1.1 mrg * disklabel). This depends on <sys/disklabel.h> and
10 1.1 mrg * DIOCSDINFO and supporting types as provided by NetBSD.
11 1.1 mrg *
12 1.1 mrg * GNUC_ATTRIBUTE
13 1.1 mrg * NO_GNUC_ATTRIBUTE
14 1.1 mrg * Use, or don't use, GNU C's __attribute__ mechanism.
15 1.1 mrg * This is presently also overloaded to control use of
16 1.1 mrg * __inline__.
17 1.1 mrg *
18 1.1 mrg * NO_TERMCAP_WIDTH
19 1.1 mrg * Never try to use tgetnum() to get the terminal's width.
20 1.1 mrg */
21 1.1 mrg
22 1.1 mrg #ifdef DISTRIB
23 1.1 mrg
24 1.1 mrg /* This code compensates for a lack of __progname, by using argv[0]
25 1.1 mrg instead. Define DISTRIB if you're on a system with no __progname. */
26 1.1 mrg const char *__progname;
27 1.1 mrg int main(int, char **);
28 1.1 mrg int main_(int, char **);
29 1.2 mrg int main(int ac, char **av) { __progname = av[0]; return main_(ac,av); }
30 1.1 mrg #define main main_
31 1.1 mrg
32 1.1 mrg #endif
33 1.1 mrg
34 1.1 mrg /* If neither S_COMMAND nor NO_S_COMMAND is defined, guess. */
35 1.1 mrg #if !defined(S_COMMAND) && !defined(NO_S_COMMAND)
36 1.1 mrg #ifdef __NetBSD__
37 1.1 mrg #define S_COMMAND
38 1.2 mrg #include <util.h>
39 1.1 mrg #endif
40 1.1 mrg #endif
41 1.1 mrg
42 1.1 mrg /* If neither GNUC_ATTRIBUTE nor NO_GNUC_ATTRIBUTE is defined, guess. */
43 1.1 mrg #if !defined(GNUC_ATTRIBUTE) && !defined(NO_GNUC_ATTRIBUTE)
44 1.1 mrg #if defined(__GNUC__) && \
45 1.1 mrg ( (__GNUC__ > 2) || \
46 1.1 mrg ( (__GNUC__ == 2) && \
47 1.1 mrg defined(__GNUC_MINOR__) && \
48 1.1 mrg (__GNUC_MINOR__ >= 7) ) )
49 1.1 mrg #define GNUC_ATTRIBUTE
50 1.1 mrg #endif
51 1.1 mrg #endif
52 1.1 mrg
53 1.1 mrg #include <stdio.h>
54 1.1 mrg #include <errno.h>
55 1.1 mrg #include <ctype.h>
56 1.1 mrg #include <stdlib.h>
57 1.1 mrg #include <unistd.h>
58 1.1 mrg #include <termcap.h>
59 1.1 mrg #include <strings.h>
60 1.1 mrg #include <sys/file.h>
61 1.1 mrg #include <sys/ioctl.h>
62 1.1 mrg
63 1.1 mrg #ifdef S_COMMAND
64 1.1 mrg #include <sys/disklabel.h>
65 1.1 mrg #endif
66 1.1 mrg
67 1.1 mrg #ifdef GNUC_ATTRIBUTE
68 1.1 mrg #define UNUSED(x) x __attribute__ ((__unused__))
69 1.1 mrg #define ATTRIB(x) __attribute__ (x)
70 1.1 mrg #define INLINE __inline__
71 1.1 mrg #else
72 1.1 mrg #define UNUSED(x) x
73 1.1 mrg #define ATTRIB(x)
74 1.1 mrg #define INLINE
75 1.1 mrg #endif
76 1.1 mrg
77 1.1 mrg extern const char *__progname;
78 1.1 mrg
79 1.1 mrg /* NPART is the total number of partitions. This must be <=43, given the
80 1.1 mrg amount of space available to store extended partitions. It also must
81 1.1 mrg be <=26, given the use of single letters to name partitions. The 8 is
82 1.1 mrg the number of `standard' partitions; this arguably should be a #define,
83 1.1 mrg since it occurs not only here but scattered throughout the code. */
84 1.1 mrg #define NPART 16
85 1.1 mrg #define NXPART (NPART-8)
86 1.1 mrg #define PARTLETTER(i) ((i)+'a')
87 1.1 mrg #define LETTERPART(i) ((i)-'a')
88 1.1 mrg
89 1.1 mrg /* Struct types. */
90 1.1 mrg typedef struct field FIELD;
91 1.1 mrg typedef struct label LABEL;
92 1.1 mrg typedef struct part PART;
93 1.1 mrg
94 1.1 mrg /*
95 1.1 mrg * A partition. We keep redundant information around, making sure that
96 1.1 mrg * whenever we change one, we keep another constant and update the
97 1.1 mrg * third. Which one is which depends. Arguably a partition should
98 1.1 mrg * also know its partition number; here, if we need that we cheat,
99 1.1 mrg * using (effectively) ptr-&label.partitions[0].
100 1.1 mrg */
101 1.1 mrg struct part {
102 1.1 mrg unsigned int startcyl;
103 1.1 mrg unsigned int nblk;
104 1.1 mrg unsigned int endcyl;
105 1.1 mrg } ;
106 1.1 mrg
107 1.1 mrg /*
108 1.1 mrg * A label. As the embedded comments indicate, much of this structure
109 1.1 mrg * corresponds directly to Sun's struct dk_label. Some of the values
110 1.1 mrg * here are historical holdovers. Apparently really old Suns did
111 1.1 mrg * their own sparing in software, so a sector or two per cylinder,
112 1.1 mrg * plus a whole cylinder or two at the end, got set aside as spares.
113 1.1 mrg * acyl and apc count those spares, and this is also why ncyl and pcyl
114 1.1 mrg * both exist. These days the spares generally are hidden from the
115 1.1 mrg * host by the disk, and there's no reason not to set
116 1.1 mrg * ncyl=pcyl=ceil(device size/spc) and acyl=apc=0.
117 1.1 mrg *
118 1.1 mrg * Note also that the geometry assumptions behind having nhead and
119 1.1 mrg * nsect assume that the sect/trk and trk/cyl values are constant
120 1.1 mrg * across the whole drive. The latter is still usually true; the
121 1.1 mrg * former isn't. In my experience, you can just put fixed values
122 1.1 mrg * here; the basis for software knowing the drive geometry is also
123 1.1 mrg * mostly invalid these days anyway. (I just use nhead=32 nsect=64,
124 1.1 mrg * which gives me 1M "cylinders", a convenient size.)
125 1.1 mrg */
126 1.1 mrg struct label {
127 1.1 mrg /* BEGIN fields taken directly from struct dk_label */
128 1.1 mrg char asciilabel[128];
129 1.1 mrg unsigned int rpm; /* Spindle rotation speed - arguably useless now */
130 1.1 mrg unsigned int pcyl; /* Physical cylinders */
131 1.1 mrg unsigned int apc; /* Alternative sectors per cylinder */
132 1.1 mrg unsigned int obs1; /* Obsolete? */
133 1.1 mrg unsigned int obs2; /* Obsolete? */
134 1.1 mrg unsigned int intrlv; /* Interleave - never anything but 1 IME */
135 1.1 mrg unsigned int ncyl; /* Number of usable cylinders */
136 1.1 mrg unsigned int acyl; /* Alternative cylinders - pcyl minus ncyl */
137 1.1 mrg unsigned int nhead; /* Tracks-per-cylinder (usually # of heads) */
138 1.1 mrg unsigned int nsect; /* Sectors-per-track */
139 1.1 mrg unsigned int obs3; /* Obsolete? */
140 1.1 mrg unsigned int obs4; /* Obsolete? */
141 1.1 mrg /* END fields taken directly from struct dk_label */
142 1.1 mrg unsigned int spc; /* Sectors per cylinder - nhead*nsect */
143 1.1 mrg unsigned int dirty : 1; /* Modified since last read */
144 1.1 mrg PART partitions[NPART]; /* The partitions themselves */
145 1.1 mrg } ;
146 1.1 mrg
147 1.1 mrg /*
148 1.1 mrg * Describes a field in the label.
149 1.1 mrg *
150 1.1 mrg * tag is a short name for the field, like "apc" or "nsect". loc is a
151 1.1 mrg * pointer to the place in the label where it's stored. print is a
152 1.1 mrg * function to print the value; the second argument is the current
153 1.1 mrg * column number, and the return value is the new current column
154 1.1 mrg * number. (This allows print functions to do proper line wrapping.)
155 1.1 mrg * chval is called to change a field; the first argument is the
156 1.1 mrg * command line portion that contains the new value (in text form).
157 1.1 mrg * The chval function is responsible for parsing and error-checking as
158 1.1 mrg * well as doing the modification. changed is a function which does
159 1.1 mrg * field-specific actions necessary when the field has been changed.
160 1.1 mrg * This could be rolled into the chval function, but I believe this
161 1.1 mrg * way provides better code sharing.
162 1.1 mrg *
163 1.1 mrg * Note that while the fields in the label vary in size (8, 16, or 32
164 1.1 mrg * bits), we store everything as ints in the label struct, above, and
165 1.1 mrg * convert when packing and unpacking. This allows us to have only
166 1.1 mrg * one numeric chval function.
167 1.1 mrg */
168 1.1 mrg struct field {
169 1.1 mrg const char *tag;
170 1.1 mrg void *loc;
171 1.1 mrg int (*print)(FIELD *, int);
172 1.1 mrg void (*chval)(const char *, FIELD *);
173 1.1 mrg void (*changed)(void);
174 1.1 mrg int taglen;
175 1.1 mrg } ;
176 1.1 mrg
177 1.1 mrg /* LABEL_MAGIC was chosen by Sun and cannot be trivially changed. */
178 1.1 mrg #define LABEL_MAGIC 0xdabe
179 1.1 mrg /* LABEL_XMAGIC needs to agree between here and any other code that uses
180 1.1 mrg extended partitions (mainly the kernel). */
181 1.1 mrg #define LABEL_XMAGIC (0x199d1fe2+8)
182 1.1 mrg
183 1.1 mrg static int diskfd; /* fd on the disk */
184 1.1 mrg static const char *diskname; /* name of the disk, for messages */
185 1.1 mrg static int readonly; /* true iff it's open RO */
186 1.1 mrg static unsigned char labelbuf[512]; /* Buffer holding the label sector */
187 1.1 mrg static LABEL label; /* The label itself. */
188 1.1 mrg static int fixmagic; /* True iff -fixmagic, ignore bad magic #s */
189 1.1 mrg static int fixcksum; /* True iff -fixcksum, ignore bad cksums */
190 1.1 mrg static int newlabel; /* True iff -new, ignore all on-disk values */
191 1.1 mrg static int quiet; /* True iff -quiet, don't print chatter */
192 1.1 mrg
193 1.1 mrg /*
194 1.1 mrg * The various functions that go in the field function pointers. The
195 1.1 mrg * _ascii functions are for 128-byte string fields (the ASCII label);
196 1.1 mrg * the _int functions are for int-valued fields (everything else).
197 1.1 mrg * update_spc is a `changed' function for updating the spc value when
198 1.1 mrg * changing one of the two values that make it up.
199 1.1 mrg */
200 1.1 mrg static int print_ascii(FIELD *, int);
201 1.1 mrg static void chval_ascii(const char *, FIELD *);
202 1.1 mrg static int print_int(FIELD *, int);
203 1.1 mrg static void chval_int(const char *, FIELD *);
204 1.1 mrg static void update_spc(void);
205 1.1 mrg
206 1.1 mrg /* The fields themselves. */
207 1.1 mrg static FIELD fields[]
208 1.1 mrg = { { "ascii", &label.asciilabel[0], print_ascii, chval_ascii, 0 },
209 1.1 mrg { "rpm", &label.rpm, print_int, chval_int, 0 },
210 1.1 mrg { "pcyl", &label.pcyl, print_int, chval_int, 0 },
211 1.1 mrg { "apc", &label.apc, print_int, chval_int, 0 },
212 1.1 mrg { "obs1", &label.obs1, print_int, chval_int, 0 },
213 1.1 mrg { "obs2", &label.obs2, print_int, chval_int, 0 },
214 1.1 mrg { "intrlv", &label.intrlv, print_int, chval_int, 0 },
215 1.1 mrg { "ncyl", &label.ncyl, print_int, chval_int, 0 },
216 1.1 mrg { "acyl", &label.acyl, print_int, chval_int, 0 },
217 1.1 mrg { "nhead", &label.nhead, print_int, chval_int, update_spc },
218 1.1 mrg { "nsect", &label.nsect, print_int, chval_int, update_spc },
219 1.1 mrg { "obs3", &label.obs3, print_int, chval_int, 0 },
220 1.1 mrg { "obs4", &label.obs4, print_int, chval_int, 0 },
221 1.1 mrg { 0 } };
222 1.1 mrg
223 1.1 mrg /*
224 1.1 mrg * We'd _like_ to use howmany() from the include files, but can't count
225 1.1 mrg * on its being present or working.
226 1.1 mrg */
227 1.1 mrg static INLINE unsigned int how_many(unsigned int, unsigned int)
228 1.1 mrg ATTRIB((__const__));
229 1.1 mrg static INLINE unsigned int how_many(unsigned int amt, unsigned int unit)
230 1.1 mrg {
231 1.1 mrg return((amt+unit-1)/unit);
232 1.1 mrg }
233 1.1 mrg
234 1.1 mrg /*
235 1.1 mrg * Try opening the disk, given a name. If mustsucceed is true, we
236 1.1 mrg * "cannot fail"; failures produce gripe-and-exit, and if we return,
237 1.1 mrg * our return value is 1. Otherwise, we return 1 on success and 0 on
238 1.1 mrg * failure.
239 1.1 mrg */
240 1.1 mrg static int trydisk(const char *s, int mustsucceed)
241 1.1 mrg {
242 1.1 mrg int ro;
243 1.1 mrg
244 1.1 mrg ro = 0;
245 1.1 mrg diskname = s;
246 1.1 mrg diskfd = open(s,O_RDWR,0);
247 1.1 mrg if (diskfd < 0)
248 1.1 mrg { diskfd = open(s,O_RDWR|O_NDELAY,0);
249 1.1 mrg }
250 1.1 mrg if (diskfd < 0)
251 1.1 mrg { diskfd = open(s,O_RDONLY,0);
252 1.1 mrg ro = 1;
253 1.1 mrg }
254 1.1 mrg if (diskfd < 0)
255 1.1 mrg { if (mustsucceed)
256 1.1 mrg { fprintf(stderr,"%s: can't open %s: %s\n",__progname,s,strerror(errno));
257 1.1 mrg exit(1);
258 1.1 mrg }
259 1.1 mrg return(0);
260 1.1 mrg }
261 1.1 mrg if (ro && !quiet) fprintf(stderr,"Note: no write access, label is readonly\n");
262 1.1 mrg readonly = ro;
263 1.1 mrg return(1);
264 1.1 mrg }
265 1.1 mrg
266 1.1 mrg /*
267 1.1 mrg * Set the disk device, given the user-supplied string. Note that even
268 1.1 mrg * if we malloc, we never free, because either trydisk eventually
269 1.1 mrg * succeeds, in which case the string is saved in diskname, or it
270 1.1 mrg * fails, in which case we exit and freeing is irrelevant.
271 1.1 mrg */
272 1.1 mrg static void setdisk(const char *s)
273 1.1 mrg {
274 1.1 mrg char *tmp;
275 1.1 mrg
276 1.1 mrg if (index(s,'/'))
277 1.1 mrg { trydisk(s,1);
278 1.1 mrg return;
279 1.1 mrg }
280 1.1 mrg if (trydisk(s,0)) return;
281 1.1 mrg tmp = malloc(strlen(s)+7);
282 1.1 mrg sprintf(tmp,"/dev/%s",s);
283 1.1 mrg if (trydisk(tmp,0)) return;
284 1.1 mrg sprintf(tmp,"/dev/%sc",s);
285 1.1 mrg if (trydisk(tmp,0)) return;
286 1.1 mrg fprintf(stderr,"%s: can't find device for disk %s\n",__progname,s);
287 1.1 mrg exit(1);
288 1.1 mrg }
289 1.1 mrg
290 1.2 mrg static void usage(void)
291 1.2 mrg {
292 1.2 mrg fprintf(stderr,"Usage: %s [options] [disk]\n",__progname);
293 1.2 mrg fprintf(stderr,"Options:\n");
294 1.2 mrg fprintf(stderr,"\t-disk <disk> Use disk <disk>.\n");
295 1.2 mrg fprintf(stderr,"\t-fixmagic Allow broken magic numbers.\n");
296 1.2 mrg fprintf(stderr,"\t-fixsum Allow broken check sums.\n");
297 1.2 mrg fprintf(stderr,"\t-new Ignore currently label.\n");
298 1.2 mrg fprintf(stderr,"\t-q Quiet mode.\n");
299 1.2 mrg fprintf(stderr,"\t-h Print this help.\n");
300 1.2 mrg }
301 1.2 mrg
302 1.1 mrg /*
303 1.1 mrg * Handle command-line arguments. We can have at most one non-flag
304 1.1 mrg * argument, which is the disk name; we can also have flags
305 1.1 mrg *
306 1.1 mrg * -disk diskdev
307 1.1 mrg * Specifies disk device unambiguously (if it begins with
308 1.1 mrg * a dash, it will be mistaken for a flag if simply placed
309 1.1 mrg * on the command line).
310 1.1 mrg *
311 1.1 mrg * -fixmagic
312 1.1 mrg * Turns on fixmagic, which causes bad magic numbers to be
313 1.1 mrg * ignored (though a complaint is still printed), rather
314 1.1 mrg * than being fatal errors.
315 1.1 mrg *
316 1.1 mrg * -fixsum
317 1.1 mrg * Turns on fixcksum, which causes bad checksums to be
318 1.1 mrg * ignored (though a complaint is still printed), rather
319 1.1 mrg * than being fatal errors.
320 1.1 mrg *
321 1.1 mrg * -new
322 1.1 mrg * Turns on newlabel, which means we're creating a new
323 1.1 mrg * label and anything in the label sector should be
324 1.1 mrg * ignored. This is a bit like -fixmagic -fixsum, except
325 1.1 mrg * that it doesn't print complaints and it ignores
326 1.1 mrg * possible garbage on-disk.
327 1.1 mrg *
328 1.1 mrg * -q
329 1.1 mrg * Turns on quiet, which suppresses printing of prompts
330 1.1 mrg * and other irrelevant chatter. If you're trying to use
331 1.1 mrg * sunlabel in an automated way, you probably want this.
332 1.2 mrg *
333 1.2 mrg * -h
334 1.2 mrg * Print a usage message.
335 1.1 mrg */
336 1.1 mrg static void handleargs(int ac, char **av)
337 1.1 mrg {
338 1.1 mrg int skip;
339 1.1 mrg int errs;
340 1.1 mrg int argno;
341 1.1 mrg
342 1.1 mrg skip = 0;
343 1.1 mrg errs = 0;
344 1.1 mrg argno = 0;
345 1.1 mrg for (ac--,av++;ac;ac--,av++)
346 1.1 mrg { if (skip > 0)
347 1.1 mrg { skip --;
348 1.1 mrg continue;
349 1.1 mrg }
350 1.1 mrg if (**av != '-')
351 1.1 mrg { switch (argno++)
352 1.1 mrg { case 0:
353 1.1 mrg setdisk(*av);
354 1.1 mrg break;
355 1.1 mrg default:
356 1.1 mrg fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av);
357 1.1 mrg errs ++;
358 1.1 mrg break;
359 1.1 mrg }
360 1.1 mrg continue;
361 1.1 mrg }
362 1.1 mrg if (0)
363 1.1 mrg {
364 1.1 mrg needarg:;
365 1.1 mrg fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av);
366 1.1 mrg errs ++;
367 1.1 mrg continue;
368 1.1 mrg }
369 1.1 mrg #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0)
370 1.1 mrg if (!strcmp(*av,"-disk"))
371 1.1 mrg { WANTARG();
372 1.1 mrg setdisk(av[skip]);
373 1.1 mrg continue;
374 1.1 mrg }
375 1.1 mrg if (!strcmp(*av,"-fixmagic"))
376 1.1 mrg { fixmagic = 1;
377 1.1 mrg continue;
378 1.1 mrg }
379 1.1 mrg if (!strcmp(*av,"-fixsum"))
380 1.1 mrg { fixcksum = 1;
381 1.1 mrg continue;
382 1.1 mrg }
383 1.1 mrg if (!strcmp(*av,"-new"))
384 1.1 mrg { newlabel = 1;
385 1.1 mrg continue;
386 1.1 mrg }
387 1.1 mrg if (!strcmp(*av,"-q"))
388 1.1 mrg { quiet = 1;
389 1.1 mrg continue;
390 1.1 mrg }
391 1.2 mrg if (!strcmp(*av,"-h"))
392 1.2 mrg { usage();
393 1.2 mrg exit(0);
394 1.2 mrg }
395 1.1 mrg #undef WANTARG
396 1.1 mrg fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av);
397 1.1 mrg errs ++;
398 1.1 mrg }
399 1.1 mrg if (errs)
400 1.1 mrg { exit(1);
401 1.1 mrg }
402 1.1 mrg }
403 1.1 mrg
404 1.1 mrg /*
405 1.1 mrg * Sets the ending cylinder for a partition. This exists mainly to
406 1.1 mrg * centralize the check. (If spc is zero, cylinder numbers make
407 1.1 mrg * little sense, and the code would otherwise die on divide-by-0 if we
408 1.1 mrg * barged blindly ahead.) We need to call this on a partition
409 1.1 mrg * whenever we change it; we need to call it on all partitions
410 1.1 mrg * whenever we change spc.
411 1.1 mrg */
412 1.1 mrg static void set_endcyl(PART *p)
413 1.1 mrg {
414 1.1 mrg if (label.spc == 0)
415 1.1 mrg { p->endcyl = p->startcyl;
416 1.1 mrg }
417 1.1 mrg else
418 1.1 mrg { p->endcyl = p->startcyl + how_many(p->nblk,label.spc);
419 1.1 mrg }
420 1.1 mrg }
421 1.1 mrg
422 1.1 mrg /*
423 1.1 mrg * Unpack a label from disk into the in-core label structure. If
424 1.1 mrg * newlabel is set, we don't actually do so; we just synthesize a
425 1.1 mrg * blank label instead. This is where knowledge of the Sun label
426 1.1 mrg * format is kept for read; pack_label is the corresponding routine
427 1.1 mrg * for write. We are careful to use labelbuf, l_s, or l_l as
428 1.1 mrg * appropriate to avoid byte-sex issues, so we can work on
429 1.1 mrg * little-endian machines.
430 1.1 mrg *
431 1.1 mrg * Note that a bad magic number for the extended partition information
432 1.1 mrg * is not considered an error; it simply indicates there is no
433 1.1 mrg * extended partition information. Arguably this is the Wrong Thing,
434 1.1 mrg * and we should take zero as meaning no info, and anything other than
435 1.1 mrg * zero or LABEL_XMAGIC as reason to gripe.
436 1.1 mrg */
437 1.1 mrg static const char *unpack_label(void)
438 1.1 mrg {
439 1.1 mrg unsigned short int l_s[256];
440 1.1 mrg unsigned long int l_l[128];
441 1.1 mrg int i;
442 1.1 mrg unsigned long int sum;
443 1.1 mrg int have_x;
444 1.1 mrg
445 1.1 mrg if (newlabel)
446 1.1 mrg { bzero(&label.asciilabel[0],128);
447 1.1 mrg label.rpm = 0;
448 1.1 mrg label.pcyl = 0;
449 1.1 mrg label.apc = 0;
450 1.1 mrg label.obs1 = 0;
451 1.1 mrg label.obs2 = 0;
452 1.1 mrg label.intrlv = 0;
453 1.1 mrg label.ncyl = 0;
454 1.1 mrg label.acyl = 0;
455 1.1 mrg label.nhead = 0;
456 1.1 mrg label.nsect = 0;
457 1.1 mrg label.obs3 = 0;
458 1.1 mrg label.obs4 = 0;
459 1.1 mrg for (i=0;i<NPART;i++)
460 1.1 mrg { label.partitions[i].startcyl = 0;
461 1.1 mrg label.partitions[i].nblk = 0;
462 1.1 mrg set_endcyl(&label.partitions[i]);
463 1.1 mrg }
464 1.1 mrg label.spc = 0;
465 1.1 mrg label.dirty = 1;
466 1.1 mrg return(0);
467 1.1 mrg }
468 1.1 mrg for (i=0;i<256;i++) l_s[i] = (labelbuf[i+i] << 8) | labelbuf[i+i+1];
469 1.1 mrg for (i=0;i<128;i++) l_l[i] = (l_s[i+i] << 16) | l_s[i+i+1];
470 1.1 mrg if (l_s[254] != LABEL_MAGIC)
471 1.1 mrg { if (fixmagic)
472 1.1 mrg { label.dirty = 1;
473 1.1 mrg printf("(ignoring incorrect magic number)\n");
474 1.1 mrg }
475 1.1 mrg else
476 1.1 mrg { return("bad magic number");
477 1.1 mrg }
478 1.1 mrg }
479 1.1 mrg sum = 0;
480 1.1 mrg for (i=0;i<256;i++) sum ^= l_s[i];
481 1.1 mrg label.dirty = 0;
482 1.1 mrg if (sum != 0)
483 1.1 mrg { if (fixcksum)
484 1.1 mrg { label.dirty = 1;
485 1.1 mrg printf("(ignoring incorrect checksum)\n");
486 1.1 mrg }
487 1.1 mrg else
488 1.1 mrg { return("checksum wrong");
489 1.1 mrg }
490 1.1 mrg }
491 1.1 mrg bcopy(&labelbuf[0],&label.asciilabel[0],128);
492 1.1 mrg label.rpm = l_s[210];
493 1.1 mrg label.pcyl = l_s[211];
494 1.1 mrg label.apc = l_s[212];
495 1.1 mrg label.obs1 = l_s[213];
496 1.1 mrg label.obs2 = l_s[214];
497 1.1 mrg label.intrlv = l_s[215];
498 1.1 mrg label.ncyl = l_s[216];
499 1.1 mrg label.acyl = l_s[217];
500 1.1 mrg label.nhead = l_s[218];
501 1.1 mrg label.nsect = l_s[219];
502 1.1 mrg label.obs3 = l_s[220];
503 1.1 mrg label.obs4 = l_s[221];
504 1.1 mrg label.spc = label.nhead * label.nsect;
505 1.1 mrg for (i=0;i<8;i++)
506 1.1 mrg { label.partitions[i].startcyl = l_l[i+i+111];
507 1.1 mrg label.partitions[i].nblk = l_l[i+i+112];
508 1.1 mrg set_endcyl(&label.partitions[i]);
509 1.1 mrg }
510 1.1 mrg have_x = 0;
511 1.1 mrg if (l_l[33] == LABEL_XMAGIC)
512 1.1 mrg { sum = 0;
513 1.1 mrg for (i=0;i<((NXPART*2)+1);i++) sum += l_l[33+i];
514 1.1 mrg if (sum != l_l[32])
515 1.1 mrg { if (fixcksum)
516 1.1 mrg { label.dirty = 1;
517 1.1 mrg printf("(ignoring incorrect extended-partition checksum)\n");
518 1.1 mrg have_x = 1;
519 1.1 mrg }
520 1.1 mrg else
521 1.1 mrg { printf("(note: extended-partition magic right but checksum wrong)\n");
522 1.1 mrg }
523 1.1 mrg }
524 1.1 mrg else
525 1.1 mrg { have_x = 1;
526 1.1 mrg }
527 1.1 mrg }
528 1.1 mrg if (have_x)
529 1.1 mrg { for (i=0;i<NXPART;i++)
530 1.1 mrg { label.partitions[i+8].startcyl = l_l[i+i+34];
531 1.1 mrg label.partitions[i+8].nblk = l_l[i+i+35];
532 1.1 mrg set_endcyl(&label.partitions[i+8]);
533 1.1 mrg }
534 1.1 mrg }
535 1.1 mrg else
536 1.1 mrg { for (i=0;i<NXPART;i++)
537 1.1 mrg { label.partitions[i+8].startcyl = 0;
538 1.1 mrg label.partitions[i+8].nblk = 0;
539 1.1 mrg set_endcyl(&label.partitions[i+8]);
540 1.1 mrg }
541 1.1 mrg }
542 1.1 mrg return(0);
543 1.1 mrg }
544 1.1 mrg
545 1.1 mrg /*
546 1.1 mrg * Pack a label from the in-core label structure into on-disk format.
547 1.1 mrg * This is where knowledge of the Sun label format is kept for write;
548 1.1 mrg * unpack_label is the corresponding routine for read. If all
549 1.1 mrg * partitions past the first 8 are size=0 cyl=0, we store all-0s in
550 1.1 mrg * the extended partition space, to be fully compatible with Sun
551 1.1 mrg * labels. Since AFIAK nothing works in that case that would break if
552 1.1 mrg * we put extended partition info there in the same format we'd use if
553 1.1 mrg * there were real info there, this is arguably unnecessary, but it's
554 1.1 mrg * easy to do.
555 1.1 mrg *
556 1.1 mrg * We are careful to avoid endianness issues by constructing everything
557 1.1 mrg * in an array of shorts. We do this rather than using chars or longs
558 1.1 mrg * because the checksum is defined in terms of shorts; using chars or
559 1.1 mrg * longs would simplify small amounts of code at the price of
560 1.1 mrg * complicating more.
561 1.1 mrg */
562 1.1 mrg static void pack_label(void)
563 1.1 mrg {
564 1.1 mrg unsigned short int l_s[256];
565 1.1 mrg int i;
566 1.1 mrg unsigned short int sum;
567 1.1 mrg
568 1.1 mrg bzero(&l_s[0],512);
569 1.1 mrg bcopy(&label.asciilabel[0],&labelbuf[0],128);
570 1.1 mrg for (i=0;i<64;i++) l_s[i] = (labelbuf[i+i] << 8) | labelbuf[i+i+1];
571 1.1 mrg l_s[210] = label.rpm;
572 1.1 mrg l_s[211] = label.pcyl;
573 1.1 mrg l_s[212] = label.apc;
574 1.1 mrg l_s[213] = label.obs1;
575 1.1 mrg l_s[214] = label.obs2;
576 1.1 mrg l_s[215] = label.intrlv;
577 1.1 mrg l_s[216] = label.ncyl;
578 1.1 mrg l_s[217] = label.acyl;
579 1.1 mrg l_s[218] = label.nhead;
580 1.1 mrg l_s[219] = label.nsect;
581 1.1 mrg l_s[220] = label.obs3;
582 1.1 mrg l_s[221] = label.obs4;
583 1.1 mrg for (i=0;i<8;i++)
584 1.1 mrg { l_s[(i*4)+222] = label.partitions[i].startcyl >> 16;
585 1.1 mrg l_s[(i*4)+223] = label.partitions[i].startcyl & 0xffff;
586 1.1 mrg l_s[(i*4)+224] = label.partitions[i].nblk >> 16;
587 1.1 mrg l_s[(i*4)+225] = label.partitions[i].nblk & 0xffff;
588 1.1 mrg }
589 1.1 mrg for (i=0;i<NXPART;i++)
590 1.1 mrg { if (label.partitions[i+8].startcyl || label.partitions[i+8].nblk) break;
591 1.1 mrg }
592 1.1 mrg if (i < NXPART)
593 1.1 mrg { unsigned long int xsum;
594 1.1 mrg l_s[66] = LABEL_XMAGIC >> 16;
595 1.1 mrg l_s[67] = LABEL_XMAGIC & 0xffff;
596 1.1 mrg for (i=0;i<NXPART;i++)
597 1.1 mrg { l_s[(i*4)+68] = label.partitions[i+8].startcyl >> 16;
598 1.1 mrg l_s[(i*4)+69] = label.partitions[i+8].startcyl & 0xffff;
599 1.1 mrg l_s[(i*4)+70] = label.partitions[i+8].nblk >> 16;
600 1.1 mrg l_s[(i*4)+71] = label.partitions[i+8].nblk & 0xffff;
601 1.1 mrg }
602 1.1 mrg xsum = 0;
603 1.1 mrg for (i=0;i<((NXPART*2)+1);i++) xsum += (l_s[i+i+66] << 16) | l_s[i+i+67];
604 1.1 mrg l_s[64] = xsum >> 16;
605 1.1 mrg l_s[65] = xsum & 0xffff;
606 1.1 mrg }
607 1.1 mrg l_s[254] = LABEL_MAGIC;
608 1.1 mrg sum = 0;
609 1.1 mrg for (i=0;i<255;i++) sum ^= l_s[i];
610 1.1 mrg l_s[255] = sum;
611 1.1 mrg for (i=0;i<256;i++)
612 1.1 mrg { labelbuf[i+i] = l_s[i] >> 8;
613 1.1 mrg labelbuf[i+i+1] = l_s[i] & 0xff;
614 1.1 mrg }
615 1.1 mrg }
616 1.1 mrg
617 1.1 mrg /*
618 1.1 mrg * Get the label. Read it off the disk and unpack it. This function
619 1.1 mrg * is nothing but lseek, read, unpack_label, and error checking.
620 1.1 mrg */
621 1.1 mrg static void getlabel(void)
622 1.1 mrg {
623 1.1 mrg int rv;
624 1.1 mrg const char *lerr;
625 1.1 mrg
626 1.1 mrg if (lseek(diskfd,0,L_SET) < 0)
627 1.1 mrg { fprintf(stderr,"%s: lseek to 0 on %s: %s\n",__progname,diskname,strerror(errno));
628 1.1 mrg exit(1);
629 1.1 mrg }
630 1.1 mrg rv = read(diskfd,&labelbuf[0],512);
631 1.1 mrg if (rv < 0)
632 1.1 mrg { fprintf(stderr,"%s: read label from %s: %s\n",__progname,diskname,strerror(errno));
633 1.1 mrg exit(1);
634 1.1 mrg }
635 1.1 mrg if (rv != 512)
636 1.1 mrg { fprintf(stderr,"%s: short read from %s: wanted %d, got %d\n",__progname,diskname,512,rv);
637 1.1 mrg exit(1);
638 1.1 mrg }
639 1.1 mrg lerr = unpack_label();
640 1.1 mrg if (lerr)
641 1.1 mrg { fprintf(stderr,"%s: bogus label on %s: %s\n",__progname,diskname,lerr);
642 1.1 mrg exit(1);
643 1.1 mrg }
644 1.1 mrg }
645 1.1 mrg
646 1.1 mrg /*
647 1.1 mrg * Put the label. Pack it and write it to the disk. This function is
648 1.1 mrg * little more than pack_label, lseek, write, and error checking.
649 1.1 mrg */
650 1.1 mrg static void putlabel(void)
651 1.1 mrg {
652 1.1 mrg int rv;
653 1.1 mrg
654 1.1 mrg if (readonly)
655 1.1 mrg { fprintf(stderr,"%s: no write access to %s\n",__progname,diskname);
656 1.1 mrg return;
657 1.1 mrg }
658 1.1 mrg if (lseek(diskfd,0,L_SET) < 0)
659 1.1 mrg { fprintf(stderr,"%s: lseek to 0 on %s: %s\n",__progname,diskname,strerror(errno));
660 1.1 mrg exit(1);
661 1.1 mrg }
662 1.1 mrg pack_label();
663 1.1 mrg rv = write(diskfd,&labelbuf[0],512);
664 1.1 mrg if (rv < 0)
665 1.1 mrg { fprintf(stderr,"%s: write label to %s: %s\n",__progname,diskname,strerror(errno));
666 1.1 mrg exit(1);
667 1.1 mrg }
668 1.1 mrg if (rv != 512)
669 1.1 mrg { fprintf(stderr,"%s: short write to %s: wanted %d, got %d\n",__progname,diskname,512,rv);
670 1.1 mrg exit(1);
671 1.1 mrg }
672 1.1 mrg label.dirty = 0;
673 1.1 mrg }
674 1.1 mrg
675 1.1 mrg /*
676 1.1 mrg * Skip whitespace. Used several places in the command-line parsing
677 1.1 mrg * code.
678 1.1 mrg */
679 1.1 mrg static void skipspaces(const char **cpp)
680 1.1 mrg #define cp (*cpp)
681 1.1 mrg {
682 1.1 mrg while (*cp && isspace(*cp)) cp ++;
683 1.1 mrg }
684 1.1 mrg #undef cp
685 1.1 mrg
686 1.1 mrg /*
687 1.1 mrg * Scan a number. The first arg points to the char * that's moving
688 1.1 mrg * along the string. The second arg points to where we should store
689 1.1 mrg * the result. The third arg says what we're scanning, for errors.
690 1.1 mrg * The return value is 0 on error, or nonzero if all goes well.
691 1.1 mrg */
692 1.1 mrg static int scannum(const char **cpp, unsigned int *np, const char *tag)
693 1.1 mrg #define cp (*cpp)
694 1.1 mrg {
695 1.1 mrg unsigned int v;
696 1.1 mrg int nd;
697 1.1 mrg
698 1.1 mrg skipspaces(cpp);
699 1.1 mrg v = 0;
700 1.1 mrg nd = 0;
701 1.1 mrg while (*cp && isdigit(*cp))
702 1.1 mrg { v = (10 * v) + (*cp++ - '0');
703 1.1 mrg nd ++;
704 1.1 mrg }
705 1.1 mrg if (nd == 0)
706 1.1 mrg { printf("Missing/invalid %s: %s\n",tag,cp);
707 1.1 mrg return(0);
708 1.1 mrg }
709 1.1 mrg *np = v;
710 1.1 mrg return(1);
711 1.1 mrg }
712 1.1 mrg #undef cp
713 1.1 mrg
714 1.1 mrg /*
715 1.1 mrg * Change a partition. pno is the number of the partition to change;
716 1.1 mrg * numbers is a pointer to the string containing the specification for
717 1.1 mrg * the new start and size. This always takes the form "start size",
718 1.1 mrg * where start can be
719 1.1 mrg *
720 1.1 mrg * a number
721 1.1 mrg * The partition starts at the beginning of that cylinder.
722 1.1 mrg *
723 1.1 mrg * start-X
724 1.1 mrg * The partition starts at the same place partition X does.
725 1.1 mrg *
726 1.1 mrg * end-X
727 1.1 mrg * The partition starts at the place partition X ends. If
728 1.1 mrg * partition X does not exactly on a cylinder boundary, it
729 1.1 mrg * is effectively rounded up.
730 1.1 mrg *
731 1.1 mrg * and size can be
732 1.1 mrg *
733 1.1 mrg * a number
734 1.1 mrg * The partition is that many sectors long.
735 1.1 mrg *
736 1.1 mrg * num/num/num
737 1.1 mrg * The three numbers are cyl/trk/sect counts. n1/n2/n3 is
738 1.1 mrg * equivalent to specifying a single number
739 1.1 mrg * ((n1*label.nhead)+n2)*label.nsect)+n3. In particular,
740 1.1 mrg * if label.nhead or label.nsect is zero, this has limited
741 1.1 mrg * usefulness.
742 1.1 mrg *
743 1.1 mrg * end-X
744 1.1 mrg * The partition ends where partition X ends. It is an
745 1.1 mrg * error for partition X to end before the specified start
746 1.1 mrg * point. This always goes to exactly where partition X
747 1.1 mrg * ends, even if that's partway through a cylinder.
748 1.1 mrg *
749 1.1 mrg * start-X
750 1.1 mrg * The partition extends to end exactly where partition X
751 1.1 mrg * begins. It is an error for partition X to begin before
752 1.1 mrg * the specified start point.
753 1.1 mrg *
754 1.1 mrg * size-X
755 1.1 mrg * The partition has the same size as partition X.
756 1.1 mrg *
757 1.1 mrg * If label.spc is nonzero but the partition size is not a multiple of
758 1.1 mrg * it, a warning is printed, since you usually don't want this. Most
759 1.1 mrg * often, in my experience, this comes from specifying a cylinder
760 1.1 mrg * count as a single number N instead of N/0/0.
761 1.1 mrg */
762 1.1 mrg static void chpart(int pno, const char *numbers)
763 1.1 mrg {
764 1.1 mrg unsigned int cyl0;
765 1.1 mrg unsigned int size;
766 1.1 mrg unsigned int sizec;
767 1.1 mrg unsigned int sizet;
768 1.1 mrg unsigned int sizes;
769 1.1 mrg
770 1.1 mrg skipspaces(&numbers);
771 1.1 mrg if (!bcmp(numbers,"end-",4) && numbers[4])
772 1.1 mrg { int epno;
773 1.1 mrg epno = LETTERPART(numbers[4]);
774 1.1 mrg if ((epno >= 0) && (epno < NPART))
775 1.1 mrg { cyl0 = label.partitions[epno].endcyl;
776 1.1 mrg numbers += 5;
777 1.1 mrg }
778 1.1 mrg else
779 1.1 mrg { if (! scannum(&numbers,&cyl0,"starting cylinder")) return;
780 1.1 mrg }
781 1.1 mrg }
782 1.1 mrg else if (!bcmp(numbers,"start-",6) && numbers[6])
783 1.1 mrg { int spno;
784 1.1 mrg spno = LETTERPART(numbers[6]);
785 1.1 mrg if ((spno >= 0) && (spno < NPART))
786 1.1 mrg { cyl0 = label.partitions[spno].startcyl;
787 1.1 mrg numbers += 7;
788 1.1 mrg }
789 1.1 mrg else
790 1.1 mrg { if (! scannum(&numbers,&cyl0,"starting cylinder")) return;
791 1.1 mrg }
792 1.1 mrg }
793 1.1 mrg else
794 1.1 mrg { if (! scannum(&numbers,&cyl0,"starting cylinder")) return;
795 1.1 mrg }
796 1.1 mrg skipspaces(&numbers);
797 1.1 mrg if (!bcmp(numbers,"end-",4) && numbers[4])
798 1.1 mrg { int epno;
799 1.1 mrg epno = LETTERPART(numbers[4]);
800 1.1 mrg if ((epno >= 0) && (epno < NPART))
801 1.1 mrg { if (label.partitions[epno].endcyl <= cyl0)
802 1.1 mrg { printf("Partition %c ends before cylinder %u\n",PARTLETTER(epno),cyl0);
803 1.1 mrg return;
804 1.1 mrg }
805 1.1 mrg size = label.partitions[epno].nblk;
806 1.1 mrg /* Be careful of unsigned arithmetic */
807 1.1 mrg if (cyl0 > label.partitions[epno].startcyl)
808 1.1 mrg { size -= (cyl0 - label.partitions[epno].startcyl) * label.spc;
809 1.1 mrg }
810 1.1 mrg else if (cyl0 < label.partitions[epno].startcyl)
811 1.1 mrg { size += (label.partitions[epno].startcyl - cyl0) * label.spc;
812 1.1 mrg }
813 1.1 mrg numbers += 5;
814 1.1 mrg }
815 1.1 mrg else
816 1.1 mrg { if (! scannum(&numbers,&size,"partition size")) return;
817 1.1 mrg }
818 1.1 mrg }
819 1.1 mrg else if (!bcmp(numbers,"start-",6) && numbers[6])
820 1.1 mrg { int spno;
821 1.1 mrg spno = LETTERPART(numbers[6]);
822 1.1 mrg if ((spno >= 0) && (spno < NPART))
823 1.1 mrg { if (label.partitions[spno].startcyl <= cyl0)
824 1.1 mrg { printf("Partition %c starts before cylinder %u\n",PARTLETTER(spno),cyl0);
825 1.1 mrg return;
826 1.1 mrg }
827 1.1 mrg size = (label.partitions[spno].startcyl - cyl0) * label.spc;
828 1.1 mrg numbers += 7;
829 1.1 mrg }
830 1.1 mrg else
831 1.1 mrg { if (! scannum(&numbers,&size,"partition size")) return;
832 1.1 mrg }
833 1.1 mrg }
834 1.1 mrg else if (!bcmp(numbers,"size-",5) && numbers[5])
835 1.1 mrg { int spno;
836 1.1 mrg spno = LETTERPART(numbers[5]);
837 1.1 mrg if ((spno >= 0) && (spno < NPART))
838 1.1 mrg { size = label.partitions[spno].nblk;
839 1.1 mrg numbers += 6;
840 1.1 mrg }
841 1.1 mrg else
842 1.1 mrg { if (! scannum(&numbers,&size,"partition size")) return;
843 1.1 mrg }
844 1.1 mrg }
845 1.1 mrg else
846 1.1 mrg { if (! scannum(&numbers,&size,"partition size")) return;
847 1.1 mrg skipspaces(&numbers);
848 1.1 mrg if (*numbers == '/')
849 1.1 mrg { sizec = size;
850 1.1 mrg numbers ++;
851 1.1 mrg if (! scannum(&numbers,&sizet,"partition size track value")) return;
852 1.1 mrg skipspaces(&numbers);
853 1.1 mrg if (*numbers != '/')
854 1.1 mrg { printf("invalid c/t/s syntax - no second slash\n");
855 1.1 mrg return;
856 1.1 mrg }
857 1.1 mrg numbers ++;
858 1.1 mrg if (! scannum(&numbers,&sizes,"partition size sector value")) return;
859 1.1 mrg size = sizes + (label.nsect * (sizet + (label.nhead * sizec)));
860 1.1 mrg }
861 1.1 mrg }
862 1.1 mrg if (label.spc && (size % label.spc))
863 1.1 mrg { printf("Warning: size is not a multiple of cylinder size (is %u/%u/%u)\n",size/label.spc,(size%label.spc)/label.nsect,size%label.nsect);
864 1.1 mrg }
865 1.1 mrg label.partitions[pno].startcyl = cyl0;
866 1.1 mrg label.partitions[pno].nblk = size;
867 1.1 mrg set_endcyl(&label.partitions[pno]);
868 1.1 mrg if ( (label.partitions[pno].startcyl*label.spc)+label.partitions[pno].nblk >
869 1.1 mrg label.spc*label.ncyl )
870 1.1 mrg { printf("Warning: partition extends beyond end of disk\n");
871 1.1 mrg }
872 1.1 mrg label.dirty = 1;
873 1.1 mrg }
874 1.1 mrg
875 1.1 mrg /*
876 1.1 mrg * Change a 128-byte-string field. There's currently only one such,
877 1.1 mrg * the ASCII label field.
878 1.1 mrg */
879 1.1 mrg static void chval_ascii(const char *cp, FIELD *f)
880 1.1 mrg {
881 1.1 mrg const char *nl;
882 1.1 mrg
883 1.1 mrg skipspaces(&cp);
884 1.1 mrg nl = index(cp,'\n');
885 1.1 mrg if (nl == 0) nl = cp + strlen(cp);
886 1.1 mrg if (nl-cp > 128)
887 1.1 mrg { printf("ascii label string too long - max 128 characters\n");
888 1.1 mrg }
889 1.1 mrg else
890 1.1 mrg { bzero(f->loc,128);
891 1.1 mrg bcopy(cp,f->loc,nl-cp);
892 1.1 mrg label.dirty = 1;
893 1.1 mrg }
894 1.1 mrg }
895 1.1 mrg
896 1.1 mrg /*
897 1.1 mrg * Change an int-valued field. As noted above, there's only one
898 1.1 mrg * function, regardless of the field size in the on-disk label.
899 1.1 mrg */
900 1.1 mrg static void chval_int(const char *cp, FIELD *f)
901 1.1 mrg {
902 1.1 mrg int v;
903 1.1 mrg
904 1.1 mrg if (! scannum(&cp,&v,"value")) return;
905 1.1 mrg *(unsigned int *)f->loc = v;
906 1.1 mrg label.dirty = 1;
907 1.1 mrg }
908 1.1 mrg
909 1.1 mrg /*
910 1.1 mrg * Change a field's value. The string argument contains the field name
911 1.1 mrg * and the new value in text form. Look up the field and call its
912 1.1 mrg * chval and changed functions.
913 1.1 mrg */
914 1.1 mrg static void chvalue(const char *str)
915 1.1 mrg {
916 1.1 mrg const char *cp;
917 1.1 mrg int n;
918 1.1 mrg int i;
919 1.1 mrg
920 1.1 mrg if (fields[0].taglen < 1)
921 1.1 mrg { for (i=0;fields[i].tag;i++) fields[i].taglen = strlen(fields[i].tag);
922 1.1 mrg }
923 1.1 mrg skipspaces(&str);
924 1.1 mrg cp = str;
925 1.1 mrg while (*cp && !isspace(*cp)) cp ++;
926 1.1 mrg n = cp - str;
927 1.1 mrg for (i=0;fields[i].tag;i++)
928 1.1 mrg { if ((n == fields[i].taglen) && !bcmp(str,fields[i].tag,n))
929 1.1 mrg { (*fields[i].chval)(cp,&fields[i]);
930 1.1 mrg if (fields[i].changed) (*fields[i].changed)();
931 1.1 mrg break;
932 1.1 mrg }
933 1.1 mrg }
934 1.1 mrg if (! fields[i].tag)
935 1.1 mrg { printf("bad name %.*s - see l output for names\n",n,str);
936 1.1 mrg }
937 1.1 mrg }
938 1.1 mrg
939 1.1 mrg /*
940 1.1 mrg * `changed' function for the ntrack and nsect fields; update label.spc
941 1.1 mrg * and call set_endcyl on all partitions.
942 1.1 mrg */
943 1.1 mrg static void update_spc(void)
944 1.1 mrg {
945 1.1 mrg int i;
946 1.1 mrg
947 1.1 mrg label.spc = label.nhead * label.nsect;
948 1.1 mrg for (i=0;i<NPART;i++) set_endcyl(&label.partitions[i]);
949 1.1 mrg }
950 1.1 mrg
951 1.1 mrg /*
952 1.1 mrg * Print function for 128-byte-string fields. Currently only the ASCII
953 1.1 mrg * label, but we don't depend on that.
954 1.1 mrg */
955 1.1 mrg static int print_ascii(FIELD *f, UNUSED(int sofar))
956 1.1 mrg {
957 1.1 mrg printf("%s: %.128s\n",f->tag,(char *)f->loc);
958 1.1 mrg return(0);
959 1.1 mrg }
960 1.1 mrg
961 1.1 mrg /*
962 1.1 mrg * Print an int-valued field. We are careful to do proper line wrap,
963 1.1 mrg * making each value occupy 16 columns.
964 1.1 mrg */
965 1.1 mrg static int print_int(FIELD *f, int sofar)
966 1.1 mrg {
967 1.1 mrg if (sofar >= 60)
968 1.1 mrg { printf("\n");
969 1.1 mrg sofar = 0;
970 1.1 mrg }
971 1.1 mrg printf("%s: %-*u",f->tag,14-(int)strlen(f->tag),*(unsigned int *)f->loc);
972 1.1 mrg return(sofar+16);
973 1.1 mrg }
974 1.1 mrg
975 1.1 mrg /*
976 1.1 mrg * Print the whole label. Just call the print function for each field,
977 1.1 mrg * then append a newline if necessary.
978 1.1 mrg */
979 1.1 mrg static void print_label(void)
980 1.1 mrg {
981 1.1 mrg int i;
982 1.1 mrg int c;
983 1.1 mrg
984 1.1 mrg c = 0;
985 1.1 mrg for (i=0;fields[i].tag;i++) c = (*fields[i].print)(&fields[i],c);
986 1.1 mrg if (c > 0) printf("\n");
987 1.1 mrg }
988 1.1 mrg
989 1.1 mrg /*
990 1.1 mrg * Figure out how many columns wide the screen is. We impose a minimum
991 1.1 mrg * width of 20 columns; I suspect the output code has some issues if
992 1.1 mrg * we have fewer columns than partitions.
993 1.1 mrg */
994 1.1 mrg static int screen_columns(void)
995 1.1 mrg {
996 1.1 mrg int ncols;
997 1.1 mrg #ifndef NO_TERMCAP_WIDTH
998 1.1 mrg char *term;
999 1.1 mrg char tbuf[1024];
1000 1.1 mrg #endif
1001 1.1 mrg #if defined(TIOCGWINSZ)
1002 1.1 mrg struct winsize wsz;
1003 1.1 mrg #elif defined(TIOCGSIZE)
1004 1.1 mrg struct ttysize tsz;
1005 1.1 mrg #endif
1006 1.1 mrg
1007 1.1 mrg ncols = 80;
1008 1.1 mrg #ifndef NO_TERMCAP_WIDTH
1009 1.1 mrg term = getenv("TERM");
1010 1.1 mrg if (term && (tgetent(&tbuf[0],term) == 1))
1011 1.1 mrg { int n;
1012 1.1 mrg n = tgetnum("co");
1013 1.1 mrg if (n > 1) ncols = n;
1014 1.1 mrg }
1015 1.1 mrg #endif
1016 1.1 mrg #if defined(TIOCGWINSZ)
1017 1.1 mrg if ((ioctl(1,TIOCGWINSZ,&wsz) == 0) && (wsz.ws_col > 0))
1018 1.1 mrg { ncols = wsz.ws_col;
1019 1.1 mrg }
1020 1.1 mrg #elif defined(TIOCGSIZE)
1021 1.1 mrg if ((ioctl(1,TIOCGSIZE,&tsz) == 0) && (tsz.ts_cols > 0))
1022 1.1 mrg { ncols = tsz.ts_cols;
1023 1.1 mrg }
1024 1.1 mrg #endif
1025 1.1 mrg if (ncols < 20) ncols = 20;
1026 1.1 mrg return(ncols);
1027 1.1 mrg }
1028 1.1 mrg
1029 1.1 mrg /*
1030 1.1 mrg * Print the partitions. The argument is true iff we should print all
1031 1.1 mrg * partitions, even those set start=0 size=0. We generate one line
1032 1.1 mrg * per partition (or, if all==0, per `interesting' partition), plus a
1033 1.1 mrg * visually graphic map of partition letters. Most of the hair in the
1034 1.1 mrg * visual display lies in ensuring that nothing takes up less than one
1035 1.1 mrg * character column, that if two boundaries appear visually identical,
1036 1.1 mrg * they _are_ identical. Within that constraint, we try to make the
1037 1.1 mrg * number of character columns proportional to the size....
1038 1.1 mrg */
1039 1.1 mrg static void print_part(int all)
1040 1.1 mrg {
1041 1.1 mrg int i;
1042 1.1 mrg int j;
1043 1.1 mrg int k;
1044 1.1 mrg int n;
1045 1.1 mrg int ncols;
1046 1.1 mrg int r;
1047 1.1 mrg int c;
1048 1.1 mrg unsigned int edges[2*NPART];
1049 1.1 mrg int ce[2*NPART];
1050 1.1 mrg int row[NPART];
1051 1.1 mrg unsigned char table[2*NPART][NPART];
1052 1.1 mrg char *line;
1053 1.1 mrg #define p label.partitions
1054 1.1 mrg
1055 1.1 mrg for (i=0;i<NPART;i++)
1056 1.1 mrg { if (all || label.partitions[i].startcyl || label.partitions[i].nblk)
1057 1.1 mrg { printf("%c: start cyl = %6u, size = %8u (",
1058 1.1 mrg PARTLETTER(i),
1059 1.1 mrg label.partitions[i].startcyl, label.partitions[i].nblk );
1060 1.1 mrg if (label.spc)
1061 1.1 mrg { printf("%u/%u/%u - ",
1062 1.1 mrg p[i].nblk/label.spc,
1063 1.1 mrg (p[i].nblk%label.spc)/label.nsect,
1064 1.1 mrg p[i].nblk%label.nsect );
1065 1.1 mrg }
1066 1.1 mrg printf("%gMb)\n",p[i].nblk/2048.0);
1067 1.1 mrg }
1068 1.1 mrg }
1069 1.1 mrg j = 0;
1070 1.1 mrg for (i=0;i<NPART;i++)
1071 1.1 mrg { if (p[i].nblk > 0)
1072 1.1 mrg { edges[j++] = p[i].startcyl;
1073 1.1 mrg edges[j++] = p[i].endcyl;
1074 1.1 mrg }
1075 1.1 mrg }
1076 1.1 mrg do
1077 1.1 mrg { n = 0;
1078 1.1 mrg for (i=1;i<j;i++)
1079 1.1 mrg { if (edges[i] < edges[i-1])
1080 1.1 mrg { unsigned int t;
1081 1.1 mrg t = edges[i];
1082 1.1 mrg edges[i] = edges[i-1];
1083 1.1 mrg edges[i-1] = t;
1084 1.1 mrg n ++;
1085 1.1 mrg }
1086 1.1 mrg }
1087 1.1 mrg } while (n > 0);
1088 1.1 mrg for (i=1;i<j;i++)
1089 1.1 mrg { if (edges[i] != edges[n])
1090 1.1 mrg { n ++;
1091 1.1 mrg if (n != i) edges[n] = edges[i];
1092 1.1 mrg }
1093 1.1 mrg }
1094 1.1 mrg n ++;
1095 1.1 mrg for (i=0;i<NPART;i++)
1096 1.1 mrg { if (p[i].nblk > 0)
1097 1.1 mrg { for (j=0;j<n;j++)
1098 1.1 mrg { if ( (p[i].startcyl <= edges[j]) &&
1099 1.1 mrg (p[i].endcyl > edges[j]) )
1100 1.1 mrg { table[j][i] = 1;
1101 1.1 mrg }
1102 1.1 mrg else
1103 1.1 mrg { table[j][i] = 0;
1104 1.1 mrg }
1105 1.1 mrg }
1106 1.1 mrg }
1107 1.1 mrg }
1108 1.1 mrg ncols = screen_columns() - 2;
1109 1.1 mrg for (i=0;i<n;i++) ce[i] = (edges[i] * ncols) / (double)edges[n-1];
1110 1.1 mrg for (i=1;i<n;i++) if (ce[i] <= ce[i-1]) ce[i] = ce[i-1] + 1;
1111 1.1 mrg if (ce[n-1] > ncols)
1112 1.1 mrg { ce[n-1] = ncols;
1113 1.1 mrg for (i=n-1;(i>0)&&(ce[i]<=ce[i-1]);i--) ce[i-1] = ce[i] - 1;
1114 1.1 mrg if (ce[0] < 0) for (i=0;i<n;i++) ce[i] = i;
1115 1.1 mrg }
1116 1.1 mrg printf("\n");
1117 1.1 mrg for (i=0;i<NPART;i++)
1118 1.1 mrg { if (p[i].nblk > 0)
1119 1.1 mrg { r = -1;
1120 1.1 mrg do
1121 1.1 mrg { r ++;
1122 1.1 mrg for (j=i-1;j>=0;j--)
1123 1.1 mrg { if (row[j] != r) continue;
1124 1.1 mrg for (k=0;k<n;k++) if (table[k][i] && table[k][j]) break;
1125 1.1 mrg if (k < n) break;
1126 1.1 mrg }
1127 1.1 mrg } while (j >= 0);
1128 1.1 mrg row[i] = r;
1129 1.1 mrg }
1130 1.1 mrg else
1131 1.1 mrg { row[i] = -1;
1132 1.1 mrg }
1133 1.1 mrg }
1134 1.1 mrg r = row[0];
1135 1.1 mrg for (i=1;i<NPART;i++) if (row[i] > r) r = row[i];
1136 1.1 mrg line = malloc(ncols+1);
1137 1.1 mrg for (i=0;i<=r;i++)
1138 1.1 mrg { for (j=0;j<ncols;j++) line[j] = ' ';
1139 1.1 mrg for (j=0;j<NPART;j++)
1140 1.1 mrg { if (row[j] != i) continue;
1141 1.1 mrg k = 0;
1142 1.1 mrg for (k=0;k<n;k++)
1143 1.1 mrg { if (table[k][j])
1144 1.1 mrg { for (c=ce[k];c<ce[k+1];c++) line[c] = 'a' + j;
1145 1.1 mrg }
1146 1.1 mrg }
1147 1.1 mrg }
1148 1.1 mrg for (j=ncols-1;(j>=0)&&(line[j]==' ');j--) ;
1149 1.1 mrg printf("%.*s\n",j+1,line);
1150 1.1 mrg }
1151 1.1 mrg free(line);
1152 1.1 mrg #undef p
1153 1.1 mrg }
1154 1.1 mrg
1155 1.1 mrg #ifdef S_COMMAND
1156 1.1 mrg /*
1157 1.1 mrg * This computes an appropriate checksum for an in-core label. It's
1158 1.1 mrg * not really related to the S command, except that it's needed only
1159 1.1 mrg * by setlabel(), which is #ifdef S_COMMAND.
1160 1.1 mrg */
1161 1.1 mrg static unsigned short int dkcksum(const struct disklabel *lp)
1162 1.1 mrg {
1163 1.1 mrg const unsigned short int *start;
1164 1.1 mrg const unsigned short int *end;
1165 1.1 mrg unsigned short int sum;
1166 1.1 mrg const unsigned short int *p;
1167 1.1 mrg
1168 1.1 mrg start = (const void *) lp;
1169 1.1 mrg end = (const void *) &lp->d_partitions[lp->d_npartitions];
1170 1.1 mrg sum = 0;
1171 1.1 mrg for (p=start;p<end;p++) sum ^= *p;
1172 1.1 mrg return(sum);
1173 1.1 mrg }
1174 1.1 mrg #endif
1175 1.1 mrg
1176 1.1 mrg #ifdef S_COMMAND
1177 1.1 mrg /*
1178 1.1 mrg * Set the in-core label. This is basically putlabel, except it builds
1179 1.1 mrg * a struct disklabel instead of a Sun label buffer, and uses
1180 1.1 mrg * DIOCSDINFO instead of lseek-and-write.
1181 1.1 mrg */
1182 1.1 mrg static void setlabel(void)
1183 1.1 mrg {
1184 1.1 mrg union {
1185 1.1 mrg struct disklabel l;
1186 1.1 mrg char pad[ sizeof(struct disklabel) -
1187 1.1 mrg (MAXPARTITIONS*sizeof(struct partition)) +
1188 1.1 mrg (16*sizeof(struct partition)) ];
1189 1.1 mrg } u;
1190 1.1 mrg int i;
1191 1.1 mrg
1192 1.1 mrg if (ioctl(diskfd,DIOCGDINFO,&u.l) < 0)
1193 1.1 mrg { printf("DIOCGDINFO: %s\n",strerror(errno));
1194 1.1 mrg return;
1195 1.1 mrg }
1196 1.1 mrg if (u.l.d_secsize != 512)
1197 1.1 mrg { printf("warning, disk claims %d-byte sectors\n",(int)u.l.d_secsize);
1198 1.1 mrg }
1199 1.1 mrg u.l.d_nsectors = label.nsect;
1200 1.1 mrg u.l.d_ntracks = label.nhead;
1201 1.1 mrg u.l.d_ncylinders = label.ncyl;
1202 1.1 mrg u.l.d_secpercyl = label.nsect * label.nhead;
1203 1.1 mrg u.l.d_rpm = label.rpm;
1204 1.1 mrg u.l.d_interleave = label.intrlv;
1205 1.2 mrg u.l.d_npartitions = getmaxpartitions();
1206 1.2 mrg bzero(&u.l.d_partitions[0],u.l.d_npartitions*sizeof(struct partition));
1207 1.2 mrg for (i=0;i<u.l.d_npartitions;i++)
1208 1.1 mrg { u.l.d_partitions[i].p_size = label.partitions[i].nblk;
1209 1.1 mrg u.l.d_partitions[i].p_offset = label.partitions[i].startcyl * label.nsect * label.nhead;
1210 1.1 mrg u.l.d_partitions[i].p_fsize = 0;
1211 1.1 mrg u.l.d_partitions[i].p_fstype = (i == 1) ? FS_SWAP :
1212 1.1 mrg (i == 2) ? FS_UNUSED :
1213 1.1 mrg FS_BSDFFS;
1214 1.1 mrg u.l.d_partitions[i].p_frag = 0;
1215 1.1 mrg u.l.d_partitions[i].p_cpg = 0;
1216 1.1 mrg }
1217 1.1 mrg u.l.d_checksum = 0;
1218 1.1 mrg u.l.d_checksum = dkcksum(&u.l);
1219 1.1 mrg if (ioctl(diskfd,DIOCSDINFO,&u.l) < 0)
1220 1.1 mrg { printf("DIOCSDINFO: %s\n",strerror(errno));
1221 1.1 mrg return;
1222 1.1 mrg }
1223 1.1 mrg }
1224 1.1 mrg #endif
1225 1.1 mrg
1226 1.1 mrg /*
1227 1.1 mrg * Read and execute one command line from the user.
1228 1.1 mrg */
1229 1.1 mrg static void docmd(void)
1230 1.1 mrg {
1231 1.1 mrg char cmdline[512];
1232 1.1 mrg
1233 1.1 mrg if (! quiet) printf("sunlabel> ");
1234 1.1 mrg if (fgets(&cmdline[0],sizeof(cmdline),stdin) != &cmdline[0]) exit(0);
1235 1.1 mrg switch (cmdline[0])
1236 1.1 mrg { case '?':
1237 1.1 mrg printf("? - print this help\n");
1238 1.1 mrg printf("L - print label, except for partition table\n");
1239 1.1 mrg printf("P - print partition table\n");
1240 1.1 mrg printf("PP - print partition table including size=0 offset=0 entries\n");
1241 1.1 mrg printf("[abcdefghijklmnop] <cylno> <size> - change partition\n");
1242 1.1 mrg printf("V <name> <value> - change a non-partition label value\n");
1243 1.1 mrg printf("W - write (possibly modified) label out\n");
1244 1.1 mrg #ifdef S_COMMAND
1245 1.1 mrg printf("S - set label in the kernel (orthogonal to W)\n");
1246 1.1 mrg #endif
1247 1.1 mrg printf("Q - quit program (error if no write since last change)\n");
1248 1.1 mrg printf("Q! - quit program (unconditionally) [EOF also quits]\n");
1249 1.1 mrg break;
1250 1.1 mrg case 'L':
1251 1.1 mrg print_label();
1252 1.1 mrg break;
1253 1.1 mrg case 'P':
1254 1.1 mrg print_part(cmdline[1]=='P');
1255 1.1 mrg break;
1256 1.1 mrg case 'W':
1257 1.1 mrg putlabel();
1258 1.1 mrg break;
1259 1.1 mrg case 'S':
1260 1.1 mrg #ifdef S_COMMAND
1261 1.1 mrg setlabel();
1262 1.1 mrg #else
1263 1.1 mrg printf("This compilation doesn't support S.\n");
1264 1.1 mrg #endif
1265 1.1 mrg break;
1266 1.1 mrg case 'Q':
1267 1.1 mrg if ((cmdline[1] == '!') || !label.dirty) exit(0);
1268 1.1 mrg printf("Label is dirty - use w to write it, or Q! to quit anyway.\n");
1269 1.1 mrg break;
1270 1.1 mrg case 'a': case 'b': case 'c': case 'd':
1271 1.1 mrg case 'e': case 'f': case 'g': case 'h':
1272 1.1 mrg case 'i': case 'j': case 'k': case 'l':
1273 1.1 mrg case 'm': case 'n': case 'o': case 'p':
1274 1.1 mrg chpart(LETTERPART(cmdline[0]),&cmdline[1]);
1275 1.1 mrg break;
1276 1.1 mrg case 'V':
1277 1.1 mrg chvalue(&cmdline[1]);
1278 1.1 mrg break;
1279 1.1 mrg case '\n':
1280 1.1 mrg break;
1281 1.1 mrg default:
1282 1.1 mrg printf("(Unrecognized command character %c ignored.)\n",cmdline[0]);
1283 1.1 mrg break;
1284 1.1 mrg }
1285 1.1 mrg }
1286 1.1 mrg
1287 1.1 mrg /*
1288 1.1 mrg * main() (duh!). Pretty boring.
1289 1.1 mrg */
1290 1.1 mrg int main(int, char **);
1291 1.1 mrg int main(int ac, char **av)
1292 1.1 mrg {
1293 1.1 mrg handleargs(ac,av);
1294 1.1 mrg getlabel();
1295 1.1 mrg while (1) docmd();
1296 1.1 mrg }
1297