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