summaryrefslogblamecommitdiffstats
path: root/mount/fsprobe.c
blob: 04e267f33f8ce12d9d1bd979e0f55fd76cdfd72b (plain) (tree)
1
2
3
4
5
6
7
8
9






                      
                      
                    
                                                 
                
 
                                                                      








                                
                                         






























                                                        
             
                          
                  
                    



                                                                 
                             



            


                                                              
   

                                                
                 
                 

                 
                                                








                                                     
     
               

 

                                                        
                                                          

                                                             
   



                                                                           
 
                                                                       

                     
                                   
                   



                      
                                                  



                                       
 







                                                                               








                                                               
                                                
                                         

                                                                 
                                            
                                            
                                    
                                                                 
                                                                       
                                                


                                                     
                                                                                 
                                                 




                                              
                              





                               
 








                                                  


                                     
































                                                                                           

                                     


















                                                                         
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "pathnames.h"
#include "fsprobe.h"
#include "sundries.h"		/* for xstrdup */
#include "nls.h"

/* list of already tested filesystems by fsprobe_procfsloop_mount() */
static struct tried {
	struct tried *next;
	char *type;
} *tried = NULL;

static int
was_tested(const char *fstype) {
	struct tried *t;

	if (fsprobe_known_fstype(fstype))
		return 1;
	for (t = tried; t; t = t->next) {
		if (!strcmp(t->type, fstype))
			return 1;
	}
	return 0;
}

static void
set_tested(const char *fstype) {
	struct tried *t = xmalloc(sizeof(struct tried));

	t->next = tried;
	t->type = xstrdup(fstype);
	tried = t;
}

static void
free_tested(void) {
	struct tried *t, *tt;

	t = tried;
	while(t) {
		free(t->type);
		tt = t->next;
		free(t);
		t = tt;
	}
	tried = NULL;
}

static char *
procfsnext(FILE *procfs) {
   char line[100];
   char fsname[100];

   while (fgets(line, sizeof(line), procfs)) {
      if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
      if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
      return xstrdup(fsname);
   }
   return 0;
}

/* Only use /proc/filesystems here, this is meant to test what
   the kernel knows about, so /etc/filesystems is irrelevant.
   Return: 1: yes, 0: no, -1: cannot open procfs */
int
fsprobe_known_fstype_in_procfs(const char *type)
{
    FILE *procfs;
    char *fsname;
    int ret = -1;

    procfs = fopen(_PATH_PROC_FILESYSTEMS, "r");
    if (procfs) {
	ret = 0;
	while ((fsname = procfsnext(procfs)) != NULL)
	    if (!strcmp(fsname, type)) {
		ret = 1;
		break;
	    }
	fclose(procfs);
	procfs = NULL;
    }
    return ret;
}

/* Try all types in FILESYSTEMS, except those in *types,
   in case *types starts with "no" */
/* return: 0: OK, -1: error in errno, 1: type not found */
/* when 0 or -1 is returned, *types contains the type used */
/* when 1 is returned, *types is NULL */
int
fsprobe_procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *),
			 struct mountargs *args,
			 const char **types,
			 int *special, int *status)
{
	char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS };
	FILE *procfs;
	char *fsname;
	const char *notypes = NULL;
	int no = 0;
	int ret = 1;
	int errsv = 0;
	int i;

	if (*types && !strncmp(*types, "no", 2)) {
		no = 1;
		notypes = (*types) + 2;
	}
	*types = NULL;

	/* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
	 * (/etc/filesystems) does not exist.  In some cases trying a
	 * filesystem that the kernel knows about on the wrong data will crash
	 * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
	 * filesystems that we are allowed to try, and in the order they should
	 * be tried.  End _PATH_FILESYSTEMS with a line containing a single '*'
	 * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
	 */
	for (i=0; i<2; i++) {
		procfs = fopen(files[i], "r");
		if (!procfs)
			continue;
		while ((fsname = procfsnext(procfs)) != NULL) {
			if (!strcmp(fsname, "*")) {
				fclose(procfs);
				goto nexti;
			}
			if (was_tested (fsname))
				continue;
			if (no && matching_type(fsname, notypes))
				continue;
			set_tested (fsname);
			args->type = fsname;
			if (verbose)
				printf(_("Trying %s\n"), fsname);
			if ((*mount_fn) (args, special, status) == 0) {
				*types = fsname;
				ret = 0;
				break;
			} else if (errno != EINVAL &&
				   fsprobe_known_fstype_in_procfs(fsname) == 1) {
				*types = "guess";
				ret = -1;
				errsv = errno;
				break;
			}
		}
		free_tested();
		fclose(procfs);
		errno = errsv;
		return ret;
	nexti:;
	}
	return 1;
}

const char *
fsprobe_get_devname_for_mounting(const char *spec)
{
	char *name, *value;

	if (!spec)
		return NULL;

	if (is_pseudo_fs(spec))
		return xstrdup(spec);

	if (parse_spec(spec, &name, &value) != 0)
		return NULL;				/* parse error */

	if (name) {
		const char *nspec = NULL;

		if (!strcmp(name,"LABEL"))
			nspec = fsprobe_get_devname_by_label(value);
		else if (!strcmp(name,"UUID"))
			nspec = fsprobe_get_devname_by_uuid(value);

		if (nspec && verbose > 1)
			printf(_("mount: going to mount %s by %s\n"), spec, name);

		free((void *) name);
		return nspec;
	}

	/* no LABEL, no UUID, .. probably a path */
	if (verbose > 1)
		printf(_("mount: no LABEL=, no UUID=, going to mount %s by path\n"), spec);

	return canonicalize(spec);
}

/* like fsprobe_get_devname_for_mounting(), but without verbose messages */
const char *
fsprobe_get_devname(const char *spec)
{
	char *name, *value;

	if (!spec)
		return NULL;
	if (is_pseudo_fs(spec))
		return xstrdup(spec);

	if (parse_spec(spec, &name, &value) != 0)
		return NULL;				/* parse error */

	if (name) {
		const char *nspec = NULL;

		if (!strcmp(name,"LABEL"))
			nspec = fsprobe_get_devname_by_label(value);
		else if (!strcmp(name,"UUID"))
			nspec = fsprobe_get_devname_by_uuid(value);

		free((void *) name);
		return nspec;
	}

	return canonicalize(spec);
}