Home | History | Annotate | Download | only in support
      1 /*
      2  * plausible.c --- Figure out if a pathname is ext* or something else.
      3  *
      4  * Copyright 2014, Oracle, Inc.
      5  *
      6  * Some parts are:
      7  * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
      8  *
      9  * %Begin-Header%
     10  * This file may be redistributed under the terms of the GNU Public
     11  * License.
     12  * %End-Header%
     13  */
     14 
     15 #ifndef _LARGEFILE_SOURCE
     16 #define _LARGEFILE_SOURCE
     17 #endif
     18 #ifndef _LARGEFILE64_SOURCE
     19 #define _LARGEFILE64_SOURCE
     20 #endif
     21 
     22 #include "config.h"
     23 #include <fcntl.h>
     24 #include <time.h>
     25 #include <sys/types.h>
     26 #ifdef HAVE_SYS_STAT_H
     27 #include <sys/stat.h>
     28 #endif
     29 #ifdef HAVE_UNISTD_H
     30 #include <unistd.h>
     31 #endif
     32 #ifdef HAVE_MAGIC_H
     33 #include <magic.h>
     34 #endif
     35 #include "plausible.h"
     36 #include "ext2fs/ext2fs.h"
     37 #include "nls-enable.h"
     38 #include "blkid/blkid.h"
     39 
     40 #ifdef HAVE_MAGIC_H
     41 static magic_t (*dl_magic_open)(int);
     42 static const char *(*dl_magic_file)(magic_t, const char *);
     43 static int (*dl_magic_load)(magic_t, const char *);
     44 static void (*dl_magic_close)(magic_t);
     45 
     46 #ifdef HAVE_DLOPEN
     47 #include <dlfcn.h>
     48 
     49 static void *magic_handle;
     50 
     51 static int magic_library_available(void)
     52 {
     53 	if (!magic_handle) {
     54 		magic_handle = dlopen("libmagic.so.1", RTLD_NOW);
     55 		if (!magic_handle)
     56 			return 0;
     57 
     58 		dl_magic_open = (magic_t (*)(int))
     59 			dlsym(magic_handle, "magic_open");
     60 		dl_magic_file = (const char *(*)(magic_t, const char *))
     61 			dlsym(magic_handle, "magic_file");
     62 		dl_magic_load = (int (*)(magic_t, const char *))
     63 			dlsym(magic_handle, "magic_load");
     64 		dl_magic_close = (void (*)(magic_t))
     65 			dlsym(magic_handle, "magic_close");
     66 	}
     67 
     68 	if (!dl_magic_open || !dl_magic_file ||
     69 	    !dl_magic_load || !dl_magic_close)
     70 		return 0;
     71 	return 1;
     72 }
     73 #else
     74 static int magic_library_available(void)
     75 {
     76 	dl_magic_open = magic_open;
     77 	dl_magic_file = magic_file;
     78 	dl_magic_load = magic_load;
     79 	dl_magic_close = magic_close;
     80 
     81 	return 1;
     82 }
     83 #endif
     84 #endif
     85 
     86 static void print_ext2_info(const char *device)
     87 
     88 {
     89 	struct ext2_super_block	*sb;
     90 	ext2_filsys		fs;
     91 	errcode_t		retval;
     92 	time_t			tm;
     93 	char			buf[80];
     94 
     95 	retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0,
     96 			      unix_io_manager, &fs);
     97 	if (retval)
     98 		return;
     99 	sb = fs->super;
    100 
    101 	if (sb->s_mtime) {
    102 		tm = sb->s_mtime;
    103 		if (sb->s_last_mounted[0]) {
    104 			memset(buf, 0, sizeof(buf));
    105 			strncpy(buf, sb->s_last_mounted,
    106 				sizeof(sb->s_last_mounted));
    107 			printf(_("\tlast mounted on %s on %s"), buf,
    108 			       ctime(&tm));
    109 		} else
    110 			printf(_("\tlast mounted on %s"), ctime(&tm));
    111 	} else if (sb->s_mkfs_time) {
    112 		tm = sb->s_mkfs_time;
    113 		printf(_("\tcreated on %s"), ctime(&tm));
    114 	} else if (sb->s_wtime) {
    115 		tm = sb->s_wtime;
    116 		printf(_("\tlast modified on %s"), ctime(&tm));
    117 	}
    118 	ext2fs_close_free(&fs);
    119 }
    120 
    121 /*
    122  * return 1 if there is no partition table, 0 if a partition table is
    123  * detected, and -1 on an error.
    124  */
    125 #ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS
    126 static int check_partition_table(const char *device)
    127 {
    128 	blkid_probe pr;
    129 	const char *value;
    130 	int ret;
    131 
    132 	pr = blkid_new_probe_from_filename(device);
    133 	if (!pr)
    134 		return -1;
    135 
    136 	ret = blkid_probe_enable_partitions(pr, 1);
    137 	if (ret < 0)
    138 		goto errout;
    139 
    140 	ret = blkid_probe_enable_superblocks(pr, 0);
    141 	if (ret < 0)
    142 		goto errout;
    143 
    144 	ret = blkid_do_fullprobe(pr);
    145 	if (ret < 0)
    146 		goto errout;
    147 
    148 	ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL);
    149 	if (ret == 0)
    150 		fprintf(stderr, _("Found a %s partition table in %s\n"),
    151 			value, device);
    152 	else
    153 		ret = 1;
    154 
    155 errout:
    156 	blkid_free_probe(pr);
    157 	return ret;
    158 }
    159 #else
    160 static int check_partition_table(const char *device EXT2FS_ATTR((unused)))
    161 {
    162 	return -1;
    163 }
    164 #endif
    165 
    166 /*
    167  * return 1 if the device looks plausible, creating the file if necessary
    168  */
    169 int check_plausibility(const char *device, int flags, int *ret_is_dev)
    170 {
    171 	int fd, ret, is_dev = 0;
    172 	ext2fs_struct_stat s;
    173 	int fl = O_RDONLY;
    174 	blkid_cache cache = NULL;
    175 	char *fs_type = NULL;
    176 	char *fs_label = NULL;
    177 
    178 	fd = ext2fs_open_file(device, fl, 0666);
    179 	if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) {
    180 		fprintf(stderr, _("The file %s does not exist and no "
    181 				  "size was specified.\n"), device);
    182 		exit(1);
    183 	}
    184 	if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) {
    185 		fl |= O_CREAT;
    186 		fd = ext2fs_open_file(device, fl, 0666);
    187 		if (fd >= 0 && (flags & VERBOSE_CREATE))
    188 			printf(_("Creating regular file %s\n"), device);
    189 	}
    190 	if (fd < 0) {
    191 		fprintf(stderr, _("Could not open %s: %s\n"),
    192 			device, error_message(errno));
    193 		if (errno == ENOENT)
    194 			fputs(_("\nThe device apparently does not exist; "
    195 				"did you specify it correctly?\n"), stderr);
    196 		exit(1);
    197 	}
    198 
    199 	if (ext2fs_fstat(fd, &s) < 0) {
    200 		perror("stat");
    201 		exit(1);
    202 	}
    203 	close(fd);
    204 
    205 	if (S_ISBLK(s.st_mode))
    206 		is_dev = 1;
    207 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    208 	/* On FreeBSD, all disk devices are character specials */
    209 	if (S_ISCHR(s.st_mode))
    210 		is_dev = 1;
    211 #endif
    212 	if (ret_is_dev)
    213 		*ret_is_dev = is_dev;
    214 
    215 	if ((flags & CHECK_BLOCK_DEV) && !is_dev) {
    216 		printf(_("%s is not a block special device.\n"), device);
    217 		return 0;
    218 	}
    219 
    220 	/*
    221 	 * Note: we use the older-style blkid API's here because we
    222 	 * want as much functionality to be available when using the
    223 	 * internal blkid library, when e2fsprogs is compiled for
    224 	 * non-Linux systems that will probably not have the libraries
    225 	 * from util-linux available.  We only use the newer
    226 	 * blkid-probe interfaces to access functionality not
    227 	 * available in the original blkid library.
    228 	 */
    229 	if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) {
    230 		fs_type = blkid_get_tag_value(cache, "TYPE", device);
    231 		if (fs_type)
    232 			fs_label = blkid_get_tag_value(cache, "LABEL", device);
    233 		blkid_put_cache(cache);
    234 	}
    235 
    236 	if (fs_type) {
    237 		if (fs_label)
    238 			printf(_("%s contains a %s file system "
    239 				 "labelled '%s'\n"), device, fs_type, fs_label);
    240 		else
    241 			printf(_("%s contains a %s file system\n"), device,
    242 			       fs_type);
    243 		if (strncmp(fs_type, "ext", 3) == 0)
    244 			print_ext2_info(device);
    245 		free(fs_type);
    246 		free(fs_label);
    247 		return 0;
    248 	}
    249 
    250 #ifdef HAVE_MAGIC_H
    251 	if ((flags & CHECK_FS_EXIST) &&
    252 	    !getenv("E2FSPROGS_LIBMAGIC_SUPPRESS") &&
    253 	    magic_library_available()) {
    254 		const char *msg;
    255 		magic_t mag;
    256 		int has_magic = 0;
    257 
    258 		mag = dl_magic_open(MAGIC_RAW | MAGIC_SYMLINK | MAGIC_DEVICES |
    259 				    MAGIC_ERROR | MAGIC_NO_CHECK_ELF |
    260 				    MAGIC_NO_CHECK_COMPRESS);
    261 		dl_magic_load(mag, NULL);
    262 
    263 		msg = dl_magic_file(mag, device);
    264 		if (msg && strcmp(msg, "data") && strcmp(msg, "empty")) {
    265 			printf(_("%s contains `%s' data\n"), device, msg);
    266 			has_magic = 1;
    267 		}
    268 
    269 		dl_magic_close(mag);
    270 		return !has_magic;
    271 	}
    272 #endif
    273 
    274 	ret = check_partition_table(device);
    275 	if (ret >= 0)
    276 		return ret;
    277 
    278 	return 1;
    279 }
    280 
    281