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