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