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