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