Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / platform / SOLARIS / fs_conv_sol26.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <stdio.h>
15
16 #define OSVERS "SunOS 5.6"
17 #include <sys/types.h>
18 #include <rx/xdr.h>
19 #include <afs/afsint.h>
20 #include <sys/param.h>
21 #include <sys/fs/ufs_fs.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <sys/mount.h>
25 #include <sys/file.h>
26 #ifndef ITIMER_REAL
27 #include <sys/time.h>
28 #endif /* ITIMER_REAL */
29 #include <time.h>
30 #ifdef AFS_VFSINCL_ENV
31 #include <sys/vnode.h>
32 #include <sys/fs/ufs_inode.h>
33 #else /* AFS_VFSINCL_ENV */
34 #include <sys/inode.h>
35 #endif /* AFS_VFSINCL_ENV */
36 #include <sys/mnttab.h>
37 #include <sys/mntent.h>
38 #include <sys/vfstab.h>
39 #include <fcntl.h>
40 #include <afs/osi_inode.h>
41 #include <errno.h>
42
43 #include <afs/nfs.h>
44 #include <afs/ihandle.h>
45 #include <afs/partition.h>
46 #include <afs/cmd.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49
50 int icount = 0, iarraysize = 0, *iarray;
51
52 char *rawname(), *unrawname(), *vol_DevName(), *blockcheck();
53 #define ROOTINODE 2
54 int force = 0, verbose = 0, unconv = 0;
55
56 static int
57 handleit(struct cmd_syndesc *as)
58 {
59 struct cmd_item *ti;
60 char *dname;
61 afs_int32 haspart = 0, hasDevice = 0;
62 struct vfstab mnt;
63
64 if (as->parms[1].items)
65 verbose = 1;
66 else
67 verbose = 0;
68 if (as->parms[2].items)
69 force = 1;
70 else
71 force = 0;
72
73 if (unconv) {
74 printf
75 ("Unconverts from a %s AFS partition to a pre-%s compatible format.\n\n",
76 OSVERS, OSVERS);
77 } else {
78 printf
79 ("Converts a pre-%s AFS partition to a %s compatible format.\n\n",
80 OSVERS, OSVERS);
81 }
82 if (!force) {
83 printf
84 ("*** Must use the '-force' option for command to have effect! ***\n");
85 if (!verbose) {
86 printf
87 ("*** Use the '-verbose' option to report what will be converted ***\n");
88 exit(1);
89 }
90 }
91
92 for (ti = as->parms[0].items; ti; ti = ti->next) {
93 FILE *fsent;
94 char *namep = ti->data;
95 int found = 0;
96
97 haspart = 1;
98 if ((fsent = fopen(VFSTAB, "r")) == NULL) {
99 printf("Unable to open %s ( errno = %d)\n", VFSTAB, errno);
100 exit(2);
101 }
102 while (!getvfsent(fsent, &mnt)) {
103 char *part = mnt.vfs_mountp;
104
105 if (!part)
106 continue;
107
108 if (!strncmp(namep, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) {
109 if (!strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) {
110 if (!strncmp(part, namep, strlen(part) + 1)) {
111 if (dname = mnt.vfs_fsckdev) {
112 printf("ProcessFileSys %s %s\n", dname, namep);
113 ProcessFileSys(dname, namep);
114 found = 1;
115 break;
116 }
117 }
118 }
119 }
120 }
121 if (!found)
122 printf("Unknown input AFS partition name or device: %s\n", namep);
123 fclose(fsent);
124 }
125
126 /* if raw devices are specified */
127 for (ti = as->parms[3].items; ti; ti = ti->next) {
128 char *namep = ti->data;
129
130 hasDevice = 1;
131 if (namep) {
132 if (!CheckMountedDevice(namep)) {
133 printf("Device %s may be mounted, aborting...\n", namep);
134 continue;
135 }
136 ProcessFileSys(namep, namep);
137 }
138 }
139
140 if (!haspart && !hasDevice) {
141 int didSome = 0;
142 FILE *fsent;
143
144 if ((fsent = fopen(VFSTAB, "r")) == NULL) {
145 printf("Unable to open %s ( errno = %d)\n", VFSTAB, errno);
146 exit(2);
147 }
148 while (!getvfsent(fsent, &mnt)) {
149 char *part = mnt.vfs_mountp;
150
151 if (!part)
152 continue;
153
154 if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE) == 0) {
155 if (dname = mnt.vfs_fsckdev)
156 ProcessFileSys(dname, part);
157 didSome++;
158 }
159 }
160 fclose(fsent);
161 if (!didSome)
162 printf
163 ("No file system partitions named %s* found; not processed\n",
164 VICE_PARTITION_PREFIX);
165 }
166 }
167
168 static int
169 ConvCmd(struct cmd_syndesc *as, void *arock)
170 {
171 unconv = 0;
172 handleit(as);
173 }
174
175 static int
176 UnConvCmd(struct cmd_syndesc *as, void *arock)
177 {
178 unconv = 1;
179 handleit(as);
180 }
181
182
183 #include "AFS_component_version_number.c"
184
185 main(argc, argv)
186 char **argv;
187 {
188 struct cmd_syndesc *ts;
189 afs_int32 code;
190
191 if (geteuid() != 0) {
192 printf("must be run as root; sorry\n");
193 exit(1);
194 }
195 ts = cmd_CreateSyntax("convert", ConvCmd, NULL, 0,
196 "Convert to AFS SunOS 5.6 format");
197 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
198 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose mode");
199 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
200 "Safeguard enforce switch");
201 cmd_AddParm(ts, "-device", CMD_LIST, CMD_OPTIONAL, "AFS raw device name");
202 ts = cmd_CreateSyntax("unconvert", UnConvCmd, NULL, 0,
203 "Convert back from AFS SunOS 5.6 to earlier formats");
204 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
205 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose mode");
206 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
207 "Safeguard enforce switch");
208 cmd_AddParm(ts, "-device", CMD_LIST, CMD_OPTIONAL, "AFS raw device name");
209
210 code = cmd_Dispatch(argc, argv);
211 exit(code);
212 }
213
214
215 ProcessFileSys(dname, path)
216 char *dname, *path;
217 {
218 struct stat status, stat1;
219 char devbuffer[120], *devname;
220 int i, j, mounted = 0, code;
221
222 if (stat(path, &status) == -1) {
223 printf("Couldn't find file system \"%s\"\n", path);
224 return;
225 }
226 if (status.st_ino == ROOTINODE) {
227 if (force) {
228 printf
229 ("Partition %s is mounted; only unmounted partitions are processed\n",
230 path);
231 return;
232 }
233 mounted = 1;
234 }
235 strcpy(devbuffer, dname);
236 devname = devbuffer;
237
238 if (stat(path, &status) == -1) {
239 printf("Couldn't find file system \"%s\"\n", path);
240 return;
241 }
242
243 if (ProcessAfsInodes(devname, path) == -1)
244 printf("Unable to get inodes for \"%s\"; not processed\n", path);
245 }
246
247
248 int
249 ProcessAfsInodes(devname, partition)
250 char *devname, *partition;
251 {
252 union {
253 struct fs fs;
254 char block[SBSIZE];
255 } super;
256 int pfd, i, c, e, bufsize, cnt = 0, mod = 0, wcnt = 0, ccnt = 0, ncnt;
257 FILE *inodeFile = NULL;
258 char rdev[25];
259 struct dinode *inodes = NULL, *einodes, *p;
260 int code, istep = 0;
261
262 sync();
263 sleep(5); /* XXXX */
264 sprintf(rdev, "%s", devname);
265 pfd = open(rdev, O_RDWR);
266 if (pfd < 0) {
267 printf("Could not read device %s to get inode list\n", rdev);
268 printf("errno %d: %s\n", errno, strerror(errno));
269 return -1;
270 }
271 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
272 printf("Unable to read superblock, partition %s\n", partition);
273 goto out;
274 }
275
276 /*
277 * run a few consistency checks of the superblock
278 * (Cribbed from vfsck)
279 */
280 if ((super.fs.fs_magic != FS_MAGIC) || (super.fs.fs_ncg < 1)
281 || (super.fs.fs_cpg < 1)
282 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
283 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
284 || (super.fs.fs_sbsize > SBSIZE)) {
285 printf
286 ("There's something wrong with the superblock for partition %s; run vfsck\n",
287 partition);
288 goto out;
289 }
290 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
291 if (!(inodes = malloc(bufsize))) {
292 printf("Unable to allocate enough memory to scan inodes; help!\n");
293 goto out;
294 }
295 einodes = (struct dinode *)(((char *)inodes) + bufsize);
296 printf("Processing all AFS inodes on partition %s (device %s)...\n",
297 partition, rdev);
298 for (c = 0; c < super.fs.fs_ncg; c++) {
299 daddr_t dblk1;
300 daddr_t f1;
301 offset_t off;
302
303 i = c * super.fs.fs_ipg;
304 e = i + super.fs.fs_ipg;
305 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
306 off = (offset_t) f1 << DEV_BSHIFT;
307 code = llseek(pfd, off, L_SET);
308 if (code == -1) {
309 printf("Error reading inodes for partition %s; run vfsck\n",
310 partition);
311 printf("%d: %s\n", errno, strerror(errno));
312 printf("file number = %d; offset = %ld\n", pfd, off);
313 goto out;
314 }
315 while (i < e) {
316 wcnt = ncnt = mod = 0;
317 code = read(pfd, inodes, bufsize);
318 if (code != bufsize) {
319 printf("Error reading inodes for partition %s; run vfsck\n",
320 partition);
321 if (code < 0) {
322 printf("errno %d: %s\n", errno, strerror(errno));
323 }
324 goto out;
325 }
326
327 /* Step through each inode */
328 for (p = inodes; p < einodes && i < e; i++, p++)
329 {
330 afs_uint32 p1, p2, p3, p4;
331 int p5;
332 quad *q;
333
334 q = (quad *) & (p->di_ic.ic_lsize);
335
336 p1 = p->di_gen;
337 p2 = p->di_ic.ic_flags;
338 p3 = q->val[0];
339 p4 = p->di_ic.ic_uid;
340 p5 = p->di_ic.ic_gid;
341
342 /* the game is afoot, Dr Watson! */
343 if (!verbose && !((ccnt + cnt + ncnt) % 5000)) {
344 printf(".");
345 fflush(stdout);
346 }
347
348 if (unconv) {
349 /*
350 * Convert from a 5.6 format to a pre 5.6 format
351 */
352 if ((p2 || p3) && !p4 && (p5 == -2)) {
353 if (verbose)
354 printf
355 ("AFS Inode %d: Already in pre-%s AFS format (%x,%x,%x,%x,%x) ignoring..\n",
356 i, OSVERS, p1, p2, p3, p4, p5);
357 ccnt++;
358 continue;
359 }
360
361 if (p5 == VICEMAGIC) {
362 /* This is a sol 2.6 AFS inode */
363 mod = 1;
364 cnt++;
365 wcnt++;
366 if (verbose)
367 printf
368 ("AFS Inode %d: %s from Sol5.6 (%x,%x,%x,%x,%x) \n",
369 i,
370 (force ? "Unconverting" :
371 "Would have unconverted"), p1, p2, p3, p4,
372 p5);
373 if (force) {
374 q->val[0] = p->di_uid;
375 p->di_uid = 0;
376 p->di_gid = -2;
377 p->di_suid = UID_LONG;
378 p->di_sgid = GID_LONG;
379 }
380 continue;
381 }
382 } else {
383 if (p5 == VICEMAGIC) { /* Assume an already converted 5.6 afs inode */
384 if (verbose)
385 printf
386 ("AFS Inode %d: Already in %s AFS format (p1=%x,p2=%x,p3=%x,p4=%x,p5=%x); ignoring..\n",
387 i, OSVERS, p1, p2, p3, p4, p5);
388 ccnt++;
389 continue;
390 }
391
392 /* for inodes created in solaris 2.4, there is a possibility
393 ** that the gid gets chopped off to an unsigned short(2 bytes)
394 */
395 if ((p2 || p3) && !p4 && ((p5 == -2)
396 || ((unsigned short)p5 ==
397 (unsigned short)-2))) {
398 /* This is a pre Sol2.6 inode */
399 mod = 1;
400 cnt++;
401 wcnt++;
402 if (verbose)
403 printf
404 ("AFS Inode %d: %s to 5.6 format (p1=%x,p2=%x,p3=%x,p4=%x, p5=%x)\n",
405 i,
406 (force ? "Converting" :
407 "Would have converted"), p1, p2, p3, p4,
408 p5);
409 if (force) {
410 p->di_gid = VICEMAGIC;
411 p->di_uid = q->val[0];
412 p->di_suid = UID_LONG;
413 p->di_sgid = GID_LONG;
414 q->val[0] = 0;
415 }
416 continue;
417 }
418 }
419 /* If not an AFS inode, ignore */
420 ncnt++;
421 if (verbose)
422 printf
423 ("Non AFS Inode %d: (p1=%x,p2=%x,p3=%x, p4=%x,p5=%x) ignoring..\n",
424 i, p1, p2, p3, p4, p5);
425 }
426
427 if (mod && force) {
428 if (lseek(pfd, -bufsize, SEEK_CUR) == -1) { /* Point to loc bef read */
429 printf("Error Seeking backwards %d bytes\n", bufsize);
430 printf("errno %d: %s\n", errno, strerror(errno));
431 goto out;
432 }
433 code = write(pfd, inodes, bufsize);
434 if (code != bufsize) { /* Update inodes */
435 printf("Error writing modified inodes for partition %s\n",
436 partition);
437 if (code < 0)
438 printf("errno %d: %s\n", errno, strerror(errno));
439 goto out;
440 }
441 if (verbose) {
442 printf
443 (" Write %d AFS inodes and %d non-AFS inodes to disk\n",
444 wcnt, ncnt);
445 }
446 }
447 }
448 }
449
450 printf("\n%s: %d AFS inodes %s ", partition, cnt,
451 (force ? "were" : "would have been"));
452 if (unconv)
453 printf("unconverted to a pre-%s format; %d already unconverted.\n",
454 OSVERS, ccnt);
455 else
456 printf("converted to a %s format; %d already converted.\n", OSVERS,
457 ccnt);
458
459 close(pfd);
460 return 0;
461
462 out:
463 close(pfd);
464 return -1;
465 }
466
467
468
469
470 int
471 bread(fd, buf, blk, size)
472 int fd;
473 char *buf;
474 daddr_t blk;
475 afs_int32 size;
476 {
477 if (lseek(fd, (off_t) dbtob(blk), L_SET) < 0
478 || read(fd, buf, size) != size) {
479 printf("bread: lseek failed (errno = %d)\n", errno);
480 return -1;
481 }
482 return 0;
483 }
484
485
486 /*
487 * Ensure that we don't have a "/" instead of a "/dev/rxd0a" type of device.
488 * returns pointer to static storage; copy it out quickly!
489 */
490 char *
491 vol_DevName(adev)
492 dev_t adev;
493 {
494 struct dirent *dp;
495 static char pbuffer[128];
496 struct stat tstat;
497 DIR *dirp;
498 char *dirName;
499 int code;
500
501 /* now, look in /dev for the appropriate file */
502 dirp = opendir(dirName = "/dev");
503 while (dp = readdir(dirp)) {
504 strcpy(pbuffer, dirName);
505 strcat(pbuffer, "/");
506 strcat(pbuffer, dp->d_name);
507 if (stat(pbuffer, &tstat) != -1 && (tstat.st_mode & S_IFMT) == S_IFBLK
508 && (tstat.st_rdev == adev)) {
509 strcpy(pbuffer, dp->d_name);
510 closedir(dirp);
511 return pbuffer;
512 }
513 }
514 closedir(dirp);
515 return NULL; /* failed */
516 }
517
518 char *
519 unrawname(name)
520 char *name;
521 {
522 char *dp;
523 struct stat stb;
524
525 if ((dp = strrchr(name, '/')) == 0)
526 return (name);
527 if (stat(name, &stb) < 0)
528 return (name);
529 if ((stb.st_mode & S_IFMT) != S_IFCHR)
530 return (name);
531 if (*(dp + 1) != 'r')
532 return (name);
533 (void)strcpy(dp + 1, dp + 2);
534 return (name);
535 }
536
537 char *
538 rawname(name)
539 char *name;
540 {
541 static char rawbuf[32];
542 char *dp;
543
544 if ((dp = strrchr(name, '/')) == 0)
545 return (0);
546 *dp = 0;
547 (void)strcpy(rawbuf, name);
548 *dp = '/';
549 (void)strcat(rawbuf, "/r");
550 (void)strcat(rawbuf, dp + 1);
551 return (rawbuf);
552 }
553
554 char *
555 blockcheck(name)
556 char *name;
557 {
558 struct stat stslash, stblock, stchar;
559 char *raw;
560 int retried = 0;
561
562 retry:
563 if (stat(name, &stblock) < 0) {
564 perror(name);
565 printf("Can't stat %s\n", name);
566 return (0);
567 }
568 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
569 raw = rawname(name);
570 if (stat(raw, &stchar) < 0) {
571 perror(raw);
572 printf("Can't stat %s\n", raw);
573 return (name);
574 }
575 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
576 return (raw);
577 } else {
578 printf("%s is not a character device\n", raw);
579 return (name);
580 }
581 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
582 name = unrawname(name);
583 retried++;
584 goto retry;
585 }
586 printf("Can't make sense out of name %s\n", name);
587 return (0);
588 }
589
590
591 /* ensure that we don't have a "/" instead of a "/dev/rxd0a" type of device.
592 * Overwrites abuffer with the corrected name.
593 */
594 EnsureDevice(abuffer)
595 char *abuffer;
596 {
597 struct dirent *dp;
598 char pbuffer[128];
599 struct stat tstat;
600 DIR *dirp;
601 char *dirName;
602 int code;
603 short dev;
604
605 code = stat(abuffer, &tstat);
606 if (code)
607 return code;
608 if (((tstat.st_mode & S_IFMT) == S_IFBLK)
609 || ((tstat.st_mode & S_IFMT) == S_IFCHR)) {
610 return 0; /* already a block or char device */
611 }
612 /* otherwise, assume we've got a normal file, and we look up its device */
613 dev = tstat.st_dev; /* remember device for this file */
614
615 /* now, look in /dev for the appropriate file */
616 dirp = opendir(dirName = "/dev");
617
618 while (dp = readdir(dirp)) {
619 strcpy(pbuffer, dirName);
620 strcat(pbuffer, "/");
621 strcat(pbuffer, dp->d_name);
622 if (stat(pbuffer, &tstat) != -1 && (tstat.st_mode & S_IFMT) == S_IFBLK
623 && (tstat.st_rdev == dev)) {
624 strcpy(abuffer, pbuffer);
625 closedir(dirp);
626 return 0;
627 }
628 }
629 closedir(dirp);
630 return 1; /* failed */
631 }
632
633 /*
634 ** Open the /etc/vfstab file to map the raw device name to the mountable
635 ** device name. Then open the /etc/mnttab file to see if this mountable
636 ** device is mounted.
637 **
638 ** Returns 1 if the conversion process should continue, otherwise returns 0
639 */
640 CheckMountedDevice(devName)
641 char *devName; /* raw device name */
642 {
643 FILE *vfsent, *mntent;
644 struct mnttab mnt;
645 struct vfstab vnt;
646 char *unRawDev = 0;
647 char YesNo = 'y';
648 int found = 0;
649
650 if ((vfsent = fopen(VFSTAB, "r")) == NULL) {
651 printf("Unable to open %s ( errno = %d)\n", VFSTAB, errno);
652 exit(2);
653 }
654 while (!getvfsent(vfsent, &vnt)) {
655 char *rawDev = vnt.vfs_fsckdev;
656 if (rawDev && !strcmp(rawDev, devName)) {
657 /* this is the device we are looking for */
658 unRawDev = vnt.vfs_special;
659 break;
660 }
661 }
662 fclose(vfsent);
663
664 if (!unRawDev)
665 goto done; /* could not find it in /etc/vfstab */
666
667 /* we found the entry in /etc/vfstab. Now we open /etc/mnnttab and
668 ** verify that it is not mounted
669 */
670 if ((mntent = fopen(MNTTAB, "r")) == NULL) {
671 printf("Unable to open %s ( errno = %d)\n", VFSTAB, errno);
672 exit(2);
673 }
674
675 while (!getmntent(mntent, &mnt)) {
676 char *resource = mnt.mnt_special;
677 if (resource && !strcmp(resource, unRawDev)) {
678 found = 1;
679 break;
680 }
681 }
682 fclose(mntent);
683
684
685 /* if we found an entry in the /etc/mnttab file, then this
686 ** device must be mounted
687 */
688 if (found) {
689 done:
690 do {
691 printf
692 ("Device %s may be mounted. Can corrupt data. Continue anyway(y/n)?",
693 devName);
694 fflush(stdout);
695 fflush(stdin);
696 YesNo = getc(stdin);
697 }
698 while (YesNo != 'y' && YesNo != 'Y' && YesNo != 'n' && YesNo != 'N');
699 }
700 if ((YesNo == 'y') || (YesNo == 'Y'))
701 return 1;
702 return 0;
703 }