0c18fd5dda2b9ef9075ce8cfae710ca59116763d
[debian/amanda] / client-src / getfsent.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998, 2001 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: getfsent.c,v 1.20.4.1.2.2.2.6 2003/03/17 18:50:11 martinea Exp $
28  *
29  * generic version of code to read fstab
30  */
31
32 #include "amanda.h"
33
34 #ifdef TEST
35 #  include <stdio.h>
36 #  include <sys/types.h>
37 #  undef P
38 #  define P(x)  x
39 #endif
40
41 #include "getfsent.h"
42
43 /*
44  * You are in a twisty maze of passages, all alike.
45  * Geesh.
46  */
47
48 #if defined(HAVE_FSTAB_H) && !defined(HAVE_MNTENT_H) /* { */
49 /*
50 ** BSD (GETFSENT_BSD)
51 */
52 #define GETFSENT_TYPE "BSD (Ultrix, AIX)"
53
54 #include <fstab.h>
55
56 int open_fstab()
57 {
58     return setfsent();
59 }
60
61 void close_fstab()
62 {
63     endfsent();
64 }
65
66
67 int get_fstab_nextentry(fsent)
68 generic_fsent_t *fsent;
69 {
70     struct fstab *sys_fsent = getfsent();
71     static char *xfsname = NULL, *xmntdir = NULL;
72     static char *xfstype = NULL, *xmntopts = NULL;
73
74     if(!sys_fsent)
75         return 0;
76     fsent->fsname  = xfsname  = newstralloc(xfsname,  sys_fsent->fs_spec);
77     fsent->mntdir  = xmntdir  = newstralloc(xmntdir,  sys_fsent->fs_file);
78     fsent->freq    = sys_fsent->fs_freq;
79     fsent->passno  = sys_fsent->fs_passno;
80 #ifdef STATFS_ULTRIX
81     fsent->fstype  = xfstype  = newstralloc(xfstype,  sys_fsent->fs_name);
82     fsent->mntopts = xmntopts = newstralloc(xmntopts, sys_fsent->fs_opts);
83 #else
84 #if defined(_AIX)
85     fsent->fstype  = xfstype  = newstralloc(xfstype,  "unknown");
86     fsent->mntopts = xmntopts = newstralloc(xmntopts, sys_fsent->fs_type);
87 #else
88     fsent->fstype  = xfstype  = newstralloc(xfstype,  sys_fsent->fs_vfstype);
89     fsent->mntopts = xmntopts = newstralloc(xmntopts, sys_fsent->fs_mntops);
90 #endif
91 #endif
92     return 1;
93 }
94
95 #else
96 #if defined(HAVE_SYS_VFSTAB_H) /* } { */
97 /*
98 ** SVR4 (GETFSENT_SOLARIS)
99 */
100 #define GETFSENT_TYPE "SVR4 (Solaris)"
101
102 #include <sys/vfstab.h>
103
104 static FILE *fstabf = NULL;
105
106 int open_fstab()
107 {
108     close_fstab();
109     return (fstabf = fopen(VFSTAB, "r")) != NULL;
110 }
111
112 void close_fstab()
113 {
114     if(fstabf)
115         afclose(fstabf);
116     fstabf = NULL;
117 }
118
119 int get_fstab_nextentry(fsent)
120 generic_fsent_t *fsent;
121 {
122     struct vfstab sys_fsent;
123
124     if(getvfsent(fstabf, &sys_fsent) != 0)
125         return 0;
126
127     fsent->fsname  = sys_fsent.vfs_special;
128     fsent->fstype  = sys_fsent.vfs_fstype;
129     fsent->mntdir  = sys_fsent.vfs_mountp;
130     fsent->mntopts = sys_fsent.vfs_mntopts;
131     fsent->freq    = 1; /* N/A */
132     fsent->passno  = sys_fsent.vfs_fsckpass? atoi(sys_fsent.vfs_fsckpass) : 0;
133     return 1;
134 }
135
136 #else
137 #  if defined(HAVE_MNTENT_H) /* } { */
138
139 /*
140 ** System V.3 (GETFSENT_SVR3, GETFSENT_LINUX)
141 */
142 #define GETFSENT_TYPE "SVR3 (NeXTstep, Irix, Linux, HP-UX)"
143
144 #include <mntent.h>
145
146 #if defined(HAVE_ENDMNTENT)
147 #define AMCLOSE_MNTENT(x)       endmntent(x)
148 #else
149 #define AMCLOSE_MNTENT(x)       fclose(x)
150 #endif
151
152 static FILE *fstabf1 = NULL;            /* /proc/mounts */
153 static FILE *fstabf2 = NULL;            /* MOUNTED */
154 static FILE *fstabf3 = NULL;            /* MNTTAB */
155
156 int open_fstab()
157 {
158     close_fstab();
159 #if defined(HAVE_SETMNTENT)
160     fstabf1 = setmntent("/proc/mounts", "r");
161 # if defined(MOUNTED)
162     fstabf2 = setmntent(MOUNTED, "r");
163 # endif
164 # if defined(MNTTAB)
165     fstabf3 = setmntent(MNTTAB, "r");
166 # endif
167 #else
168 # if defined(MNTTAB)
169     fstabf3 = fopen(MNTTAB, "r");
170 # endif
171 #endif
172     return (fstabf1 != NULL || fstabf2 != NULL || fstabf3 != NULL);
173 }
174
175 void close_fstab()
176 {
177     if (fstabf1) {
178         AMCLOSE_MNTENT(fstabf1);
179         fstabf1 = NULL;
180     }
181     if (fstabf2) {
182         AMCLOSE_MNTENT(fstabf2);
183         fstabf2 = NULL;
184     }
185     if (fstabf3) {
186         AMCLOSE_MNTENT(fstabf3);
187         fstabf3 = NULL;
188     }
189 }
190
191 int get_fstab_nextentry(fsent)
192 generic_fsent_t *fsent;
193 {
194     struct mntent *sys_fsent = NULL;
195
196     if(fstabf1) {
197         sys_fsent = getmntent(fstabf1);
198         if(!sys_fsent) {
199             AMCLOSE_MNTENT(fstabf1);
200             fstabf1 = NULL;
201         }
202     }
203     if(!sys_fsent && fstabf2) {
204         sys_fsent = getmntent(fstabf2);
205         if(!sys_fsent) {
206             AMCLOSE_MNTENT(fstabf2);
207             fstabf2 = NULL;
208         }
209     }
210     if(!sys_fsent && fstabf3) {
211         sys_fsent = getmntent(fstabf3);
212         if(!sys_fsent) {
213             AMCLOSE_MNTENT(fstabf3);
214             fstabf3 = NULL;
215         }
216     }
217     if(!sys_fsent) {
218         return 0;
219     }
220
221     fsent->fsname  = sys_fsent->mnt_fsname;
222     fsent->fstype  = sys_fsent->mnt_type;
223     fsent->mntdir  = sys_fsent->mnt_dir;
224     fsent->mntopts = sys_fsent->mnt_opts;
225     fsent->freq    = sys_fsent->mnt_freq;
226     fsent->passno  = sys_fsent->mnt_passno;
227     return 1;
228 }
229
230 #  else
231 #    if defined(HAVE_SYS_MNTTAB_H) || defined(STATFS_SCO_OS5) /* } { */
232
233 /* we won't actually include mnttab.h, since it contains nothing useful.. */
234
235 #define GETFSENT_TYPE "SVR3 (Interactive UNIX)"
236
237 #include <stdio.h>
238 #include <string.h>
239 #include <ctype.h>
240
241 #define FSTAB "/etc/fstab"
242
243 static FILE *fstabf = NULL;
244
245 int open_fstab()
246 {
247     close_fstab();
248     return (fstabf = fopen(FSTAB, "r")) != NULL;
249 }
250
251 void close_fstab()
252 {
253     if(fstabf)
254         afclose(fstabf);
255     fstabf = NULL;
256 }
257
258 static generic_fsent_t _fsent;
259
260 int get_fstab_nextentry(fsent)
261 generic_fsent_t *fsent;
262 {
263     static char *lfsnam = NULL;
264     static char *opts = NULL;
265     static char *cp = NULL;
266     char *s;
267     int ch;
268
269     amfree(cp);
270     for (; (cp = agets(fstabf)) != NULL; free(cp)) {
271         fsent->fsname = strtok(cp, " \t");
272         if ( fsent->fsname && *fsent->fsname != '#' )
273             break;
274     }
275     if (cp == NULL) return 0;
276
277     fsent->mntdir = strtok((char *)NULL, " \t");
278     fsent->mntopts = strtok((char *)NULL, " \t");
279     if ( *fsent->mntopts != '-' )  {
280         fsent->fstype = fsent->mntopts;
281         fsent->mntopts = "rw";
282     } else {
283         fsent->fstype = "";
284         if (strcmp(fsent->mntopts, "-r") == 0) {
285             fsent->mntopts = "ro";
286         }
287     }
288     if ((s = strchr(fsent->fstype, ',')) != NULL) {
289         *s++ = '\0';
290         strappend(fsent->mntopts, ",");
291         strappend(fsent->mntopts, s);
292     }
293
294     lfsnam = newstralloc(lfsnam, fsent->fstype);
295     s = lfsnam;
296     while((ch = *s++) != '\0') {
297         if(isupper(ch)) ch = tolower(ch);
298         s[-1] = ch;
299     }
300     fsent->fstype = lfsnam;
301
302 #define sc "hs"
303     if (strncmp(fsent->fstype, sc, sizeof(sc)-1) == 0)
304         fsent->fstype = "iso9660";
305 #undef sc
306
307     fsent->freq = 0;
308     fsent->passno = 0;
309
310     return 1;
311 }
312
313 #    else
314 #      if defined(HAVE_MNTTAB_H) /* } { */
315
316 #define GETFSENT_TYPE "SVR3 (SCO UNIX)"
317
318 #include <mnttab.h>
319 #include <sys/fstyp.h>
320 #include <sys/statfs.h>
321
322 #define MNTTAB "/etc/mnttab"
323
324 /*
325  * If these are defined somewhere please let me know.
326  */
327
328 #define MNT_READONLY 0101
329 #define MNT_READWRITE 0100
330
331 static FILE *fstabf = NULL;
332
333 int open_fstab()
334 {
335     close_fstab();
336     return (fstabf = fopen(MNTTAB, "r")) != NULL;
337 }
338
339 void close_fstab()
340 {
341     if(fstabf)
342         afclose(fstabf);
343     fstabf = NULL;
344 }
345
346 static generic_fsent_t _fsent;
347
348 int get_fstab_nextentry(fsent)
349 generic_fsent_t *fsent;
350 {
351     struct statfs fsd;
352     char typebuf[FSTYPSZ];
353     static struct mnttab mnt;
354     char *dp, *ep;
355
356     if(!fread (&mnt, sizeof mnt, 1, fstabf))
357       return 0;
358
359     fsent->fsname  = mnt.mt_dev;
360     fsent->mntdir  = mnt.mt_filsys;
361     fsent->fstype = "";
362
363     if (statfs (fsent->mntdir, &fsd, sizeof fsd, 0) != -1
364         && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) {
365        dp = typebuf;
366        ep = fsent->fstype = malloc(strlen(typebuf)+2);
367        while (*dp)
368             *ep++ = tolower(*dp++);
369        *ep=0;
370     }
371
372     if ( mnt.mt_ro_flg == MNT_READONLY ) {
373         fsent->mntopts = "ro";
374     } else {
375         fsent->mntopts = "rw";
376     }
377
378     fsent->freq = 0;
379     fsent->passno = 0;
380     return 1;
381 }
382
383 #      else /* } { */
384
385 #define GETFSENT_TYPE "undefined"
386
387 #      endif
388 #    endif
389 #  endif
390 #endif
391 #endif /* } */
392
393 /*
394  *=====================================================================
395  * Convert either a block or character device name to a character (raw)
396  * device name.
397  *
398  * char *dev2rdev(char *name);
399  *
400  * entry:       name - device name to convert
401  * exit:        matching character device name if found,
402  *              otherwise returns the input
403  *
404  * The input must be an absolute path.
405  *
406  * The exit string area is always an alloc-d area that the caller is
407  * responsible for releasing.
408  *=====================================================================
409  */
410
411 static char *dev2rdev(name)
412 char *name;
413 {
414   char *fname = NULL;
415   struct stat st;
416   char *s;
417   int ch;
418
419   if(stat(name, &st) == 0 && S_ISCHR(st.st_mode)) {
420     /*
421      * If the input is already a character device, just return it.
422      */
423     return stralloc(name);
424   }
425
426   s = name;
427   ch = *s++;
428
429   if(ch == '\0' || ch != '/') return stralloc(name);
430
431   ch = *s++;                                    /* start after first '/' */
432   /*
433    * Break the input path at each '/' and create a new name with an
434    * 'r' before the right part.  For instance:
435    *
436    *   /dev/sd0a -> /dev/rsd0a
437    *   /dev/dsk/c0t0d0s0 -> /dev/rdsk/c0t0d0s0 -> /dev/dsk/rc0t0d0s0
438    */
439   while(ch) {
440     if (ch == '/') {
441       s[-1] = '\0';
442       fname = newvstralloc(fname, name, "/r", s, NULL);
443       s[-1] = ch;
444       if(stat(fname, &st) == 0 && S_ISCHR(st.st_mode)) return fname;
445     }
446     ch = *s++;
447   }
448   amfree(fname);
449   return stralloc(name);                        /* no match */
450 }
451
452 static int samefile(stats, estat)
453 struct stat stats[3], *estat;
454 {
455   int i;
456   for(i = 0; i < 3; ++i) {
457     if (stats[i].st_dev == estat->st_dev &&
458         stats[i].st_ino == estat->st_ino)
459       return 1;
460   }
461   return 0;
462 }
463
464 int search_fstab(name, fsent, check_dev)
465      char *name;
466      generic_fsent_t *fsent;
467      int check_dev;
468 {
469 #ifdef IGNORE_FSTAB
470   /* There is no real mount table so this will always fail and
471    * we are using GNU tar so we can just return here.
472    */
473   return 0;
474 #else
475   struct stat stats[3];
476   char *fullname = NULL;
477   char *rdev = NULL;
478   int rc;
479
480   if (!name)
481     return 0;
482
483   stats[0].st_dev = stats[1].st_dev = stats[2].st_dev = -1;
484
485   if (stat(name, &stats[0]) == -1)
486     stats[0].st_dev = -1;
487   if (name[0] != '/') {
488     fullname = stralloc2(DEV_PREFIX, name);
489     if (stat(fullname, &stats[1]) == -1)
490       stats[1].st_dev = -1;
491     fullname = newstralloc2(fullname, RDEV_PREFIX, name);
492     if (stat(fullname, &stats[2]) == -1)
493       stats[2].st_dev = -1;
494     amfree(fullname);
495   }
496   else if (stat((rdev = dev2rdev(name)), &stats[1]) == -1)
497     stats[1].st_dev = -1;
498
499   amfree(rdev);
500
501   if (!open_fstab())
502     return 0;
503
504   rc = 0;
505   while(get_fstab_nextentry(fsent)) {
506     struct stat mntstat;
507     struct stat fsstat;
508     struct stat fsrstat;
509     int smnt = -1, sfs = -1, sfsr = -1;
510
511     amfree(rdev);
512
513     if(fsent->mntdir != NULL &&
514        (smnt = stat(fsent->mntdir, &mntstat)) == -1)
515       continue;
516
517     if(fsent->fsname != NULL) {
518       sfs = stat(fsent->fsname, &fsstat);
519       sfsr = stat((rdev = dev2rdev(fsent->fsname)), &fsrstat);
520       if(check_dev == 1 && sfs == -1 && sfsr == -1)
521         continue;
522     }
523
524     if((fsent->mntdir != NULL &&
525         smnt != -1 &&
526         samefile(stats, &mntstat)) || 
527        (fsent->fsname != NULL &&
528         sfs != -1 &&
529         samefile(stats, &fsstat)) ||
530        (fsent->fsname != NULL &&
531         sfsr != -1 &&
532         samefile(stats, &fsrstat))) {
533       rc = 1;
534       break;
535     }
536   }
537   amfree(rdev);
538   close_fstab();
539   return rc;
540 #endif /* !IGNORE_FSTAB */
541 }
542
543 int is_local_fstype(fsent)
544 generic_fsent_t *fsent;
545 {
546     if(fsent->fstype == NULL)   /* unknown, assume local */
547         return 1;
548
549     /* just eliminate fstypes known to be remote or unsavable */
550
551     return strcmp(fsent->fstype, "nfs") != 0 && /* NFS */
552            strcmp(fsent->fstype, "afs") != 0 && /* Andrew Filesystem */
553            strcmp(fsent->fstype, "swap") != 0 && /* Swap */
554            strcmp(fsent->fstype, "iso9660") != 0 && /* CDROM */
555            strcmp(fsent->fstype, "hs") != 0 && /* CDROM */
556            strcmp(fsent->fstype, "piofs") != 0; /* an AIX printer thing? */
557 }
558
559
560 char *amname_to_devname(str)
561 char *str;
562 {
563     generic_fsent_t fsent;
564
565     if(search_fstab(str, &fsent, 1) && fsent.fsname != NULL)
566         str = fsent.fsname;
567     else if(search_fstab(str, &fsent, 0) && fsent.fsname != NULL)
568         str = fsent.fsname;
569
570     return dev2rdev(str);
571 }
572
573 char *amname_to_dirname(str)
574 char *str;
575 {
576     generic_fsent_t fsent;
577
578     if(search_fstab(str, &fsent, 1) && fsent.mntdir != NULL)
579         str = fsent.mntdir;
580     else if(search_fstab(str, &fsent, 0) && fsent.mntdir != NULL)
581         str = fsent.mntdir;
582
583     return stralloc(str);
584 }
585
586 char *amname_to_fstype(str)
587 char *str;
588 {
589     generic_fsent_t fsent;
590
591     if (!search_fstab(str, &fsent, 1) && !search_fstab(str, &fsent, 0))
592       return stralloc("");
593
594     return stralloc(fsent.fstype);
595 }
596
597 #ifdef TEST
598
599 void
600 print_entry(fsent)
601 generic_fsent_t *fsent;
602 {
603 #define nchk(s) ((s)? (s) : "<NULL>")
604     printf("%-20.20s %-14.14s %-7.7s %4d %5d %s\n",
605            nchk(fsent->fsname), nchk(fsent->mntdir), nchk(fsent->fstype),
606            fsent->freq, fsent->passno, nchk(fsent->mntopts));
607 }
608
609 int main(argc, argv)
610     int argc;
611     char **argv;
612 {
613     generic_fsent_t fsent;
614     int fd;
615     char *s;
616     char *name = NULL;
617     unsigned long malloc_hist_1, malloc_size_1;
618     unsigned long malloc_hist_2, malloc_size_2;
619
620     for(fd = 3; fd < FD_SETSIZE; fd++) {
621         /*
622          * Make sure nobody spoofs us with a lot of extra open files
623          * that would cause an open we do to get a very high file
624          * descriptor, which in turn might be used as an index into
625          * an array (e.g. an fd_set).
626          */
627         close(fd);
628     }
629
630     set_pname("getfsent");
631
632     malloc_size_1 = malloc_inuse(&malloc_hist_1);
633
634     if(!open_fstab()) {
635         fprintf(stderr, "getfsent_test: could not open fstab\n");
636         return 1;
637     }
638
639     printf("getfsent (%s)\n",GETFSENT_TYPE);
640     printf("l/r fsname               mntdir         fstype  freq pass# mntopts\n");
641     while(get_fstab_nextentry(&fsent)) {
642         printf("%c  ",is_local_fstype(&fsent)? 'l' : 'r');
643         print_entry(&fsent);
644     }
645     printf("--------\n");
646
647     close_fstab();
648
649     name = newstralloc(name, "/usr");
650     if(search_fstab(name, &fsent, 1) || search_fstab(name, &fsent, 0)) {
651         printf("Found %s mount for %s:\n",
652                is_local_fstype(&fsent)? "local" : "remote", name);
653         print_entry(&fsent);
654     }
655     else 
656         printf("Mount for %s not found\n", name);
657
658     name = newstralloc(name, "/");
659     if(search_fstab(name, &fsent, 1) || search_fstab(name, &fsent, 0)) {
660         printf("Found %s mount for %s:\n",
661                is_local_fstype(&fsent)? "local" : "remote", name);
662         print_entry(&fsent);
663     }
664     else 
665         printf("Mount for %s not found\n", name);
666
667     name = newstralloc(name, "/");
668     s = amname_to_fstype(name);
669     printf("fstype of `%s': %s\n", name, s);
670     amfree(s);
671     name = newstralloc(name, "/dev/root");
672     s = amname_to_fstype(name);
673     printf("fstype of `%s': %s\n", name, s);
674     amfree(s);
675     name = newstralloc(name, "/usr");
676     s = amname_to_fstype(name);
677     printf("fstype of `%s': %s\n", name, s);
678     amfree(s);
679     name = newstralloc(name, "c0t3d0s0");
680     s = amname_to_fstype(name);
681     printf("fstype of `%s': %s\n", name, s);
682     amfree(s);
683
684     name = newstralloc(name, "/tmp/foo");
685     s = amname_to_devname(name);
686     printf("device of `%s': %s\n", name, s);
687     amfree(s);
688     s = amname_to_dirname(name);
689     printf("dirname of `%s': %s\n", name, s);
690     amfree(s);
691     s = amname_to_fstype(name);
692     printf("fstype of `%s': %s\n", name, s);
693     amfree(s);
694
695     name = newstralloc(name, "./foo");
696     s = amname_to_devname(name);
697     printf("device of `%s': %s\n", name, s);
698     amfree(s);
699     s = amname_to_dirname(name);
700     printf("dirname of `%s': %s\n", name, s);
701     amfree(s);
702     s = amname_to_fstype(name);
703     printf("fstype of `%s': %s\n", name, s);
704     amfree(s);
705
706     while (--argc > 0) {
707         name = newstralloc(name, *++argv);
708         s = amname_to_devname(name);
709         printf("device of `%s': %s\n", name, s);
710         amfree(s);
711         s = amname_to_dirname(name);
712         printf("dirname of `%s': %s\n", name, s);
713         amfree(s);
714         s = amname_to_fstype(name);
715         printf("fstype of `%s': %s\n", name, s);
716         amfree(s);
717     }
718
719     amfree(name);
720
721     malloc_size_2 = malloc_inuse(&malloc_hist_2);
722
723     if(malloc_size_1 != malloc_size_2) {
724         malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
725     }
726
727     return 0;
728 }
729
730 #endif