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