cmd: add flags argument to create syntax function
[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 }