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