chiark / gitweb /
b247fe2ddbc0211afd165a2f59ae1d108153743c
[elogind.git] / extras / volume_id / lib / volume_id.c
1 /*
2  * volume_id - reads volume label and uuid
3  *
4  * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      This program is free software; you can redistribute it and/or modify it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  */
10
11 #ifndef _GNU_SOURCE
12 #define _GNU_SOURCE 1
13 #endif
14
15 #ifdef HAVE_CONFIG_H
16 #  include <config.h>
17 #endif
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27
28 #include "libvolume_id.h"
29 #include "util.h"
30
31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
32
33 struct prober {
34         volume_id_probe_fn_t prober;
35         const char *name[4];
36 };
37
38 static const struct prober prober_raid[] = {
39         { volume_id_probe_linux_raid, { "linux_raid", } },
40         { volume_id_probe_ddf_raid, { "ddf_raid", } },
41         { volume_id_probe_intel_software_raid, { "isw_raid", } },
42         { volume_id_probe_lsi_mega_raid, { "lsi_mega_raid", } },
43         { volume_id_probe_via_raid, { "via_raid", } },
44         { volume_id_probe_silicon_medley_raid, { "silicon_medley_raid", } },
45         { volume_id_probe_nvidia_raid, { "nvidia_raid", } },
46         { volume_id_probe_promise_fasttrack_raid, { "promise_fasttrack_raid", } },
47         { volume_id_probe_highpoint_45x_raid, { "highpoint_raid", } },
48         { volume_id_probe_adaptec_raid, { "adaptec_raid", } },
49         { volume_id_probe_jmicron_raid, { "jmicron_raid", } },
50         { volume_id_probe_lvm1, { "lvm1", } },
51         { volume_id_probe_lvm2, { "lvm2", } },
52         { volume_id_probe_highpoint_37x_raid, { "highpoint_raid", } },
53 };
54
55 static const struct prober prober_filesystem[] = {
56         { volume_id_probe_vfat, { "vfat", } },
57         { volume_id_probe_linux_swap, { "swap", } },
58         { volume_id_probe_luks, { "luks", } },
59         { volume_id_probe_xfs, { "xfs", } },
60         { volume_id_probe_ext, { "ext2", "ext3", "jbd", } },
61         { volume_id_probe_reiserfs, { "reiserfs", "reiser4", } },
62         { volume_id_probe_jfs, { "jfs", } },
63         { volume_id_probe_udf, { "udf", } },
64         { volume_id_probe_iso9660, { "iso9660", } },
65         { volume_id_probe_hfs_hfsplus, { "hfs", "hfsplus", } },
66         { volume_id_probe_ufs, { "ufs", } },
67         { volume_id_probe_ntfs, { "ntfs", } },
68         { volume_id_probe_cramfs, { "cramfs", } },
69         { volume_id_probe_romfs, { "romfs", } },
70         { volume_id_probe_hpfs, { "hpfs", } },
71         { volume_id_probe_sysv, { "sysv", "xenix", } },
72         { volume_id_probe_minix, { "minix",  } },
73         { volume_id_probe_gfs, { "gfs", } },
74         { volume_id_probe_gfs2, { "gfs2", } },
75         { volume_id_probe_ocfs1, { "ocfs1", } },
76         { volume_id_probe_ocfs2, { "ocfs2", } },
77         { volume_id_probe_vxfs, { "vxfs", } },
78         { volume_id_probe_squashfs, { "squashfs", } },
79         { volume_id_probe_netware, { "netware", } },
80         { volume_id_probe_oracleasm, { "oracleasm", } },
81 };
82
83 /* the user can overwrite this log function */
84 static void default_log(int priority, const char *file, int line, const char *format, ...)
85 {
86         return;
87 }
88
89 volume_id_log_fn_t volume_id_log_fn = default_log;
90
91 /**
92  * volume_id_get_prober_by_type:
93  * @type: Type string.
94  *
95  * Lookup the probing function for a specific type.
96  *
97  * Returns: The probing function for the given type, #NULL otherwise.
98  **/
99 const volume_id_probe_fn_t *volume_id_get_prober_by_type(const char *type)
100 {
101         unsigned int p, n;
102
103         if (type == NULL)
104                 return NULL;
105
106         for (p = 0; p < ARRAY_SIZE(prober_raid); p++)
107                 for (n = 0; prober_raid[p].name[n] !=  NULL; n++)
108                         if (strcmp(type, prober_raid[p].name[n]) == 0)
109                                 return &prober_raid[p].prober;
110         for (p = 0; p < ARRAY_SIZE(prober_filesystem); p++)
111                 for (n = 0; prober_filesystem[p].name[n] !=  NULL; n++)
112                         if (strcmp(type, prober_filesystem[p].name[n]) == 0)
113                                 return &prober_filesystem[p].prober;
114         return NULL;
115 }
116
117 /**
118  * volume_id_get_label:
119  * @id: Probing context.
120  * @label: Label string. Must not be freed by the caller.
121  *
122  * Get the label string after a successful probe. Unicode
123  * is translated to UTF-8.
124  *
125  * Returns: 1 if the value was set, 0 otherwise.
126  **/
127 int volume_id_get_label(struct volume_id *id, const char **label)
128 {
129         if (id == NULL)
130                 return 0;
131         if (label == NULL)
132                 return 0;
133         if (id->usage_id == VOLUME_ID_UNUSED)
134                 return 0;
135
136         *label = id->label;
137         return 1;
138 }
139
140 /**
141  * volume_id_get_label_raw:
142  * @id: Probing context.
143  * @label: Label byte array. Must not be freed by the caller.
144  * @len: Length of raw label byte array.
145  *
146  * Get the raw label byte array after a successful probe. It may
147  * contain undecoded multibyte character streams.
148  *
149  * Returns: 1 if the value was set, 0 otherwise.
150  **/
151 int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len)
152 {
153         if (id == NULL)
154                 return 0;
155         if (label == NULL)
156                 return 0;
157         if (len == NULL)
158                 return 0;
159         if (id->usage_id == VOLUME_ID_UNUSED)
160                 return 0;
161
162         *label = id->label_raw;
163         *len = id->label_raw_len;
164         return 1;
165 }
166
167 /**
168  * volume_id_get_uuid:
169  * @id: Probing context.
170  * @uuid: UUID string. Must not be freed by the caller.
171  *
172  * Get the raw UUID string after a successful probe.
173  *
174  * Returns: 1 if the value was set, 0 otherwise.
175  **/
176 int volume_id_get_uuid(struct volume_id *id, const char **uuid)
177 {
178         if (id == NULL)
179                 return 0;
180         if (uuid == NULL)
181                 return 0;
182         if (id->usage_id == VOLUME_ID_UNUSED)
183                 return 0;
184
185         *uuid = id->uuid;
186         return 1;
187 }
188
189 /**
190  * volume_id_get_uuid_raw:
191  * @id: Probing context.
192  * @uuid: UUID byte array. Must not be freed by the caller.
193  * @len: Length of raw UUID byte array.
194  *
195  * Get the raw UUID byte array after a successful probe. It may
196  * contain unconverted endianes values.
197  *
198  * Returns: 1 if the value was set, 0 otherwise.
199  **/
200 int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len)
201 {
202         if (id == NULL)
203                 return 0;
204         if (uuid == NULL)
205                 return 0;
206         if (len == NULL)
207                 return 0;
208         if (id->usage_id == VOLUME_ID_UNUSED)
209                 return 0;
210
211         *uuid = id->uuid_raw;
212         *len = id->uuid_raw_len;
213         return 1;
214 }
215
216 /**
217  * volume_id_get_usage:
218  * @id: Probing context.
219  * @usage: Usage string. Must not be freed by the caller.
220  *
221  * Get the usage string after a successful probe.
222  *
223  * Returns: 1 if the value was set, 0 otherwise.
224  **/
225 int volume_id_get_usage(struct volume_id *id, const char **usage)
226 {
227         if (id == NULL)
228                 return 0;
229         if (usage == NULL)
230                 return 0;
231         if (id->usage_id == VOLUME_ID_UNUSED)
232                 return 0;
233
234         *usage = id->usage;
235         return 1;
236 }
237
238 /**
239  * volume_id_get_type:
240  * @id: Probing context
241  * @type: Type string. Must not be freed by the caller.
242  *
243  * Get the type string after a successful probe.
244  *
245  * Returns: 1 if the value was set, 0 otherwise.
246  **/
247 int volume_id_get_type(struct volume_id *id, const char **type)
248 {
249         if (id == NULL)
250                 return 0;
251         if (type == NULL)
252                 return 0;
253         if (id->usage_id == VOLUME_ID_UNUSED)
254                 return 0;
255
256         *type = id->type;
257         return 1;
258 }
259
260 /**
261  * volume_id_get_type_version:
262  * @id: Probing context.
263  * @type_version: Type version string. Must not be freed by the caller.
264  *
265  * Get the Type version string after a successful probe.
266  *
267  * Returns: 1 if the value was set, 0 otherwise.
268  **/
269 int volume_id_get_type_version(struct volume_id *id, const char **type_version)
270 {
271         if (id == NULL)
272                 return 0;
273         if (type_version == NULL)
274                 return 0;
275         if (id->usage_id == VOLUME_ID_UNUSED)
276                 return 0;
277
278         *type_version = id->type_version;
279         return 1;
280 }
281
282 static int needs_encoding(const char c)
283 {
284         if ((c >= '0' && c <= '9') ||
285             (c >= 'A' && c <= 'Z') ||
286             (c >= 'a' && c <= 'z') ||
287             strchr(ALLOWED_CHARS, c))
288                 return 0;
289         return 1;
290 }
291
292 /**
293  * volume_id_encode_string:
294  * @str: Input string to be encoded.
295  * @str_enc: Target string to store the encoded input.
296  * @len: Location to store the encoded string. The target string,
297  * which may be four times as long as the input string.
298  *
299  * Encode all potentially unsafe characters of a string to the
300  * corresponding hex value prefixed by '\x'.
301  *
302  * Returns: 1 if the entire string was copied, 0 otherwise.
303  **/
304 int volume_id_encode_string(const char *str, char *str_enc, size_t len)
305 {
306         size_t i, j;
307
308         if (str == NULL || str_enc == NULL || len == 0)
309                 return 0;
310
311         str_enc[0] = '\0';
312         for (i = 0, j = 0; str[i] != '\0'; i++) {
313                 int seqlen;
314
315                 seqlen = volume_id_utf8_encoded_valid_unichar(&str[i]);
316                 if (seqlen > 1) {
317                         memcpy(&str_enc[j], &str[i], seqlen);
318                         j += seqlen;
319                         i += (seqlen-1);
320                 } else if (str[i] == '\\' || needs_encoding(str[i])) {
321                         sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
322                         j += 4;
323                 } else {
324                         str_enc[j] = str[i];
325                         j++;
326                 }
327                 if (j+3 >= len)
328                         goto err;
329         }
330         str_enc[j] = '\0';
331         return 1;
332 err:
333         return 0;
334 }
335
336 /* run only once into a timeout for unreadable devices */
337 static int device_is_readable(struct volume_id *id, uint64_t off)
338 {
339         if (volume_id_get_buffer(id, off, 0x200) != NULL)
340                 return 1;
341         return 0;
342 }
343
344 /**
345  * volume_id_probe_raid:
346  * @id: Probing context.
347  * @off: Probing offset relative to the start of the device.
348  * @size: Total size of the device.
349  *
350  * Probe device for all known raid signatures.
351  *
352  * Returns: 0 on successful probe, otherwise negative value.
353  **/
354 int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
355 {
356         unsigned int i;
357
358         if (id == NULL)
359                 return -EINVAL;
360
361         if (!device_is_readable(id, off))
362                 return -1;
363
364         info("probing at offset 0x%llx, size 0x%llx\n",
365             (unsigned long long) off, (unsigned long long) size);
366
367         for (i = 0; i < ARRAY_SIZE(prober_raid); i++)
368                 if (prober_raid[i].prober(id, off, size) == 0)
369                         goto found;
370         return -1;
371
372 found:
373         /* If recognized, we free the allocated buffers */
374         volume_id_free_buffer(id);
375         return 0;
376 }
377
378 /**
379  * volume_id_probe_filesystem:
380  * @id: Probing context.
381  * @off: Probing offset relative to the start of the device.
382  * @size: Total size of the device.
383  *
384  * Probe device for all known filesystem signatures.
385  *
386  * Returns: 0 on successful probe, otherwise negative value.
387  **/
388 int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
389 {
390         unsigned int i;
391
392         if (id == NULL)
393                 return -EINVAL;
394
395         if (!device_is_readable(id, off))
396                 return -1;
397
398         info("probing at offset 0x%llx, size 0x%llx\n",
399             (unsigned long long) off, (unsigned long long) size);
400
401         for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++)
402                 if (prober_filesystem[i].prober(id, off, size) == 0)
403                         goto found;
404         return -1;
405
406 found:
407         /* If recognized, we free the allocated buffers */
408         volume_id_free_buffer(id);
409         return 0;
410 }
411
412 /**
413  * volume_id_probe_all:
414  * @id: Probing context.
415  * @off: Probing offset relative to the start of the device.
416  * @size: Total size of the device.
417  *
418  * Probe device for all known raid and filesystem signatures.
419  *
420  * Returns: 0 on successful probe, otherwise negative value.
421  **/
422 int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size)
423 {
424         if (id == NULL)
425                 return -EINVAL;
426
427         if (!device_is_readable(id, off))
428                 return -1;
429
430         /* probe for raid first, because fs probes may be successful on raid members */
431         if (volume_id_probe_raid(id, off, size) == 0)
432                 return 0;
433
434         if (volume_id_probe_filesystem(id, off, size) == 0)
435                 return 0;
436
437         return -1;
438 }
439
440 /**
441  * volume_id_probe_raid:
442  * @all_probers_fn: prober function to called for all known probing routines.
443  * @id: Context passed to prober function.
444  * @off: Offset value passed to prober function.
445  * @size: Size value passed to prober function.
446  * @data: Arbitrary data passed to the prober function.
447  *
448  * Run a custom function for all known probing routines.
449  **/
450 void volume_id_all_probers(all_probers_fn_t all_probers_fn,
451                            struct volume_id *id, uint64_t off, uint64_t size,
452                            void *data)
453 {
454         unsigned int i;
455
456         if (all_probers_fn == NULL)
457                 return;
458
459         for (i = 0; i < ARRAY_SIZE(prober_raid); i++)
460                 if (all_probers_fn(prober_raid[i].prober, id, off, size, data) != 0)
461                         goto out;
462         for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++)
463                 if (all_probers_fn(prober_filesystem[i].prober, id, off, size, data) != 0)
464                         goto out;
465 out:
466         return;
467 }
468
469 /**
470  * volume_id_open_fd:
471  * @id: Probing context.
472  * @fd: Open file descriptor of device to read from.
473  *
474  * Create the context for probing.
475  *
476  * Returns: Probing context, or #NULL on failure.
477  **/
478 struct volume_id *volume_id_open_fd(int fd)
479 {
480         struct volume_id *id;
481
482         id = malloc(sizeof(struct volume_id));
483         if (id == NULL)
484                 return NULL;
485         memset(id, 0x00, sizeof(struct volume_id));
486
487         id->fd = fd;
488
489         return id;
490 }
491
492 struct volume_id *volume_id_open_node(const char *path)
493 {
494         struct volume_id *id;
495         int fd;
496
497         fd = open(path, O_RDONLY);
498         if (fd < 0) {
499                 dbg("unable to open '%s'\n", path);
500                 return NULL;
501         }
502
503         id = volume_id_open_fd(fd);
504         if (id == NULL)
505                 return NULL;
506
507         /* close fd on device close */
508         id->fd_close = 1;
509
510         return id;
511 }
512
513 /**
514  * volume_id_close:
515  * @id: Probing context.
516  *
517  * Release probing context and free all associated data.
518  */
519 void volume_id_close(struct volume_id *id)
520 {
521         if (id == NULL)
522                 return;
523
524         if (id->fd_close != 0)
525                 close(id->fd);
526
527         volume_id_free_buffer(id);
528
529         free(id);
530 }