chiark / gitweb /
bf009c72030383b8bcbcc47ec906c3102121914b
[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 /* the user can overwrite this log function */
32 static void default_log(int priority, const char *file, int line, const char *format, ...)
33 {
34         return;
35 }
36
37 volume_id_log_fn_t volume_id_log_fn = default_log;
38
39 int volume_id_get_label(struct volume_id *id, const char **label)
40 {
41         if (id == NULL)
42                 return -EINVAL;
43         if (label == NULL)
44                 return -EINVAL;
45         if (id->usage_id == VOLUME_ID_UNUSED)
46                 return 0;
47
48         *label = id->label;
49         return 1;
50 }
51
52 int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len)
53 {
54         if (id == NULL)
55                 return -EINVAL;
56         if (label == NULL)
57                 return -EINVAL;
58         if (len == NULL)
59                 return -EINVAL;
60         if (id->usage_id == VOLUME_ID_UNUSED)
61                 return 0;
62
63         *label = id->label_raw;
64         *len = id->label_raw_len;
65         return 1;
66 }
67
68 int volume_id_get_uuid(struct volume_id *id, const char **uuid)
69 {
70         if (id == NULL)
71                 return -EINVAL;
72         if (uuid == NULL)
73                 return -EINVAL;
74         if (id->usage_id == VOLUME_ID_UNUSED)
75                 return 0;
76
77         *uuid = id->uuid;
78         return 1;
79 }
80
81 int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len)
82 {
83         if (id == NULL)
84                 return -EINVAL;
85         if (uuid == NULL)
86                 return -EINVAL;
87         if (len == NULL)
88                 return -EINVAL;
89         if (id->usage_id == VOLUME_ID_UNUSED)
90                 return 0;
91
92         *uuid = id->uuid_raw;
93         *len = id->uuid_raw_len;
94         return 1;
95 }
96
97 int volume_id_get_usage(struct volume_id *id, const char **usage)
98 {
99         if (id == NULL)
100                 return -EINVAL;
101         if (usage == NULL)
102                 return -EINVAL;
103         if (id->usage_id == VOLUME_ID_UNUSED)
104                 return 0;
105
106         *usage = id->usage;
107         return 1;
108 }
109
110 int volume_id_get_type(struct volume_id *id, const char **type)
111 {
112         if (id == NULL)
113                 return -EINVAL;
114         if (type == NULL)
115                 return -EINVAL;
116         if (id->usage_id == VOLUME_ID_UNUSED)
117                 return 0;
118
119         *type = id->type;
120         return 1;
121 }
122
123 int volume_id_get_type_version(struct volume_id *id, const char **type_version)
124 {
125         if (id == NULL)
126                 return -EINVAL;
127         if (type_version == NULL)
128                 return -EINVAL;
129         if (id->usage_id == VOLUME_ID_UNUSED)
130                 return 0;
131
132         *type_version = id->type_version;
133         return 1;
134 }
135
136 int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
137 {
138         if (id == NULL)
139                 return -EINVAL;
140
141         info("probing at offset 0x%llx, size 0x%llx",
142             (unsigned long long) off, (unsigned long long) size);
143
144         /* probe for raid first, because fs probes may be successful on raid members */
145         if (size) {
146                 if (volume_id_probe_linux_raid(id, off, size) == 0)
147                         goto found;
148
149                 if (volume_id_probe_intel_software_raid(id, off, size) == 0)
150                         goto found;
151
152                 if (volume_id_probe_lsi_mega_raid(id, off, size) == 0)
153                         goto found;
154
155                 if (volume_id_probe_via_raid(id, off, size) == 0)
156                         goto found;
157
158                 if (volume_id_probe_silicon_medley_raid(id, off, size) == 0)
159                         goto found;
160
161                 if (volume_id_probe_nvidia_raid(id, off, size) == 0)
162                         goto found;
163
164                 if (volume_id_probe_promise_fasttrack_raid(id, off, size) == 0)
165                         goto found;
166
167                 if (volume_id_probe_highpoint_45x_raid(id, off, size) == 0)
168                         goto found;
169
170                 if (volume_id_probe_adaptec_raid(id, off, size) == 0)
171                         goto found;
172
173                 if (volume_id_probe_jmicron_raid(id, off, size) == 0)
174                         goto found;
175         }
176
177         if (volume_id_probe_lvm1(id, off, size) == 0)
178                 goto found;
179
180         if (volume_id_probe_lvm2(id, off, size) == 0)
181                 goto found;
182
183         if (volume_id_probe_highpoint_37x_raid(id, off, size) == 0)
184                 goto found;
185
186         return -1;
187
188 found:
189         /* If recognized, we free the allocated buffers */
190         volume_id_free_buffer(id);
191         return 0;
192 }
193
194 int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
195 {
196         if (id == NULL)
197                 return -EINVAL;
198
199         info("probing at offset 0x%llx, size 0x%llx",
200             (unsigned long long) off, (unsigned long long) size);
201
202         if (volume_id_probe_vfat(id, off, size) == 0)
203                 goto found;
204
205         /* fill buffer with maximum */
206         volume_id_get_buffer(id, 0, SB_BUFFER_SIZE);
207
208         if (volume_id_probe_linux_swap(id, off, size) == 0)
209                 goto found;
210
211         if (volume_id_probe_luks(id, off, size) == 0)
212                 goto found;
213
214         if (volume_id_probe_xfs(id, off, size) == 0)
215                 goto found;
216
217         if (volume_id_probe_ext(id, off, size) == 0)
218                 goto found;
219
220         if (volume_id_probe_reiserfs(id, off, size) == 0)
221                 goto found;
222
223         if (volume_id_probe_jfs(id, off, size) == 0)
224                 goto found;
225
226         if (volume_id_probe_udf(id, off, size) == 0)
227                 goto found;
228
229         if (volume_id_probe_iso9660(id, off, size) == 0)
230                 goto found;
231
232         if (volume_id_probe_hfs_hfsplus(id, off, size) == 0)
233                 goto found;
234
235         if (volume_id_probe_ufs(id, off, size) == 0)
236                 goto found;
237
238         if (volume_id_probe_ntfs(id, off, size)  == 0)
239                 goto found;
240
241         if (volume_id_probe_cramfs(id, off, size) == 0)
242                 goto found;
243
244         if (volume_id_probe_romfs(id, off, size) == 0)
245                 goto found;
246
247         if (volume_id_probe_hpfs(id, off, size) == 0)
248                 goto found;
249
250         if (volume_id_probe_sysv(id, off, size) == 0)
251                 goto found;
252
253         if (volume_id_probe_minix(id, off, size) == 0)
254                 goto found;
255
256         if (volume_id_probe_ocfs1(id, off, size) == 0)
257                 goto found;
258
259         if (volume_id_probe_ocfs2(id, off, size) == 0)
260                 goto found;
261
262         if (volume_id_probe_vxfs(id, off, size) == 0)
263                 goto found;
264
265         if (volume_id_probe_squashfs(id, off, size) == 0)
266                 goto found;
267
268         if (volume_id_probe_netware(id, off, size) == 0)
269                 goto found;
270
271         if (volume_id_probe_gfs(id, off, size) == 0)
272                 goto found;
273
274         if (volume_id_probe_gfs2(id, off, size) == 0)
275                 goto found;
276
277         return -1;
278
279 found:
280         /* If recognized, we free the allocated buffers */
281         volume_id_free_buffer(id);
282         return 0;
283 }
284
285 int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size)
286 {
287         if (id == NULL)
288                 return -EINVAL;
289
290         if (volume_id_probe_raid(id, off, size) == 0)
291                 return 0;
292
293         if (volume_id_probe_filesystem(id, off, size) == 0)
294                 return 0;
295
296         return -1;
297 }
298
299 /* open volume by already open file descriptor */
300 struct volume_id *volume_id_open_fd(int fd)
301 {
302         struct volume_id *id;
303
304         id = malloc(sizeof(struct volume_id));
305         if (id == NULL)
306                 return NULL;
307         memset(id, 0x00, sizeof(struct volume_id));
308
309         id->fd = fd;
310
311         return id;
312 }
313
314 /* open volume by device node */
315 struct volume_id *volume_id_open_node(const char *path)
316 {
317         struct volume_id *id;
318         int fd;
319
320         fd = open(path, O_RDONLY);
321         if (fd < 0) {
322                 dbg("unable to open '%s'", path);
323                 return NULL;
324         }
325
326         id = volume_id_open_fd(fd);
327         if (id == NULL)
328                 return NULL;
329
330         /* close fd on device close */
331         id->fd_close = 1;
332
333         return id;
334 }
335
336 void volume_id_close(struct volume_id *id)
337 {
338         if (id == NULL)
339                 return;
340
341         if (id->fd_close != 0)
342                 close(id->fd);
343
344         volume_id_free_buffer(id);
345
346         free(id);
347 }