chiark / gitweb /
man: fix typos
[elogind.git] / extras / volume_id / vol_id.c
1 /*
2  * vol_id - read filesystem label and uuid
3  *
4  * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <getopt.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <inttypes.h>
36 #include <sys/ioctl.h>
37
38 #include "../../udev/udev.h"
39 #include "lib/libvolume_id.h"
40
41 #define BLKGETSIZE64 _IOR(0x12,114,size_t)
42
43 static int debug;
44 struct udev *udev_ctx;
45
46 static void log_fn(struct udev *udev, int priority,
47                    const char *file, int line, const char *fn,
48                    const char *format, va_list args)
49 {
50         if (debug) {
51                 fprintf(stderr, "%s: ", fn != NULL ? fn : file);
52                 vfprintf(stderr, format, args);
53         } else {
54                 vsyslog(priority, format, args);
55         }
56 }
57
58 static void vid_log(int priority, const char *file, int line, const char *format, ...)
59 {
60         va_list args;
61
62         if (priority > udev_get_log_priority(udev_ctx))
63                 return;
64         va_start(args, format);
65         log_fn(udev_ctx, priority, file, line, NULL, format, args);
66         va_end(args);
67         return;
68 }
69
70 static int all_probers(volume_id_probe_fn_t probe_fn,
71                        struct volume_id *id, uint64_t off, uint64_t size,
72                        void *data)
73 {
74         const char *type;
75
76         if (probe_fn(id, off, size) == 0)
77                 if (volume_id_get_type(id, &type))
78                         printf("%s\n", type);
79
80         return 0;
81 }
82
83 int main(int argc, char *argv[])
84 {
85         static const struct option options[] = {
86                 { "label", no_argument, NULL, 'l' },
87                 { "label-raw", no_argument, NULL, 'L' },
88                 { "uuid", no_argument, NULL, 'u' },
89                 { "type", no_argument, NULL, 't' },
90                 { "export", no_argument, NULL, 'x' },
91                 { "skip-raid", no_argument, NULL, 's' },
92                 { "size", required_argument, NULL, 'S' },
93                 { "probe-all", no_argument, NULL, 'a' },
94                 { "offset", optional_argument, NULL, 'o' },
95                 { "debug", no_argument, NULL, 'd' },
96                 { "help", no_argument, NULL, 'h' },
97                 {}
98         };
99
100         enum print_type {
101                 PRINT_EXPORT,
102                 PRINT_TYPE,
103                 PRINT_LABEL,
104                 PRINT_UUID,
105                 PRINT_LABEL_RAW,
106         } print = PRINT_EXPORT;
107
108         struct volume_id *vid = NULL;
109         char label_safe[256];
110         char label_enc[256];
111         char uuid_safe[256];
112         char uuid_enc[256];
113         char type_enc[256];
114         char type_version_enc[256];
115         uint64_t size = 0;
116         int skip_raid = 0;
117         int probe_all = 0;
118         uint64_t offset = 0;
119         const char *node;
120         int fd;
121         const char *label, *uuid, *type, *type_version, *usage;
122         int retval;
123         int rc = 0;
124
125         udev_ctx = udev_new();
126         if (udev_ctx == NULL)
127                 goto exit;
128         logging_init("vol_id");
129         udev_set_log_fn(udev_ctx, log_fn);
130
131         /* hook in our debug into libvolume_id */
132         volume_id_log_fn = vid_log;
133
134         while (1) {
135                 int option;
136
137                 option = getopt_long(argc, argv, "lLutxsS:aodh", options, NULL);
138                 if (option == -1)
139                         break;
140
141                 switch (option) {
142                 case 'd':
143                         debug = 1;
144                         if (udev_get_log_priority(udev_ctx) < LOG_INFO)
145                                 udev_set_log_priority(udev_ctx, LOG_INFO);
146                         break;
147                 case 'l':
148                         print = PRINT_LABEL;
149                         break;
150                 case 'L':
151                         print = PRINT_LABEL_RAW;
152                         break;
153                 case 'u':
154                         print = PRINT_UUID;
155                         break;
156                 case 't':
157                         print = PRINT_TYPE;
158                         break;
159                 case 'x':
160                         print = PRINT_EXPORT;
161                         break;
162                 case 's':
163                         skip_raid = 1;
164                         break;
165                 case 'a':
166                         probe_all = 1;
167                         break;
168                 case 'S':
169                         if (optarg[0] != '\0')
170                                 size = strtoull(optarg, NULL, 0);
171                         break;
172                 case 'o':
173                         if (optarg[0] != '\0')
174                                 offset = strtoull(optarg, NULL, 0);
175                         break;
176                 case 'h':
177                         printf("Usage: vol_id [options] <device>\n"
178                             " --export         export key/value pairs\n"
179                             " --type           filesystem type\n"
180                             " --label          filesystem label\n"
181                             " --label-raw      raw label\n"
182                             " --uuid           filesystem uuid\n"
183                             " --skip-raid      don't probe for raid\n"
184                             " --probe-all      find possibly conflicting signatures\n"
185                             " --offset=<bytes> probe at the given offset\n"
186                             " --size=<bytes>   overwrite device size\n"
187                             " --debug          print debug output to stderr\n"
188                             " --help\n\n");
189                         goto exit;
190                 default:
191                         retval = 1;
192                         goto exit;
193                 }
194         }
195
196         node = argv[optind];
197         if (!node) {
198                 err(udev_ctx, "no device\n");
199                 fprintf(stderr, "no device\n");
200                 rc = 1;
201                 goto exit;
202         }
203
204         fd = open(node, O_RDONLY);
205         if (fd < 0) {
206                 fprintf(stderr, "%s: error opening volume\n", node);
207                 rc = 2;
208                 goto exit;
209         }
210
211         vid = volume_id_open_fd(fd);
212         if (vid == NULL) {
213                 rc = 2;
214                 goto exit;
215         }
216
217         if (size == 0) {
218                 if (ioctl(fd, BLKGETSIZE64, &size) == 0) {
219                         info(udev_ctx, "BLKGETSIZE64=%" PRIu64 " (%" PRIu64 "GB)\n", size, size >> 30);
220                 } else {
221                         struct stat statbuf;
222
223                         if (fstat(fd, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
224                                 size = statbuf.st_size;
225                         else
226                                 size = 0;
227                         info(udev_ctx, "stat=%" PRIu64 " (%" PRIu64 "GB)\n", size, size >> 30);
228                 }
229         }
230
231         /* try to drop all privileges before reading disk content */
232         if (getuid() == 0) {
233                 struct passwd *pw;
234
235                 pw = getpwnam("nobody");
236                 if (pw != NULL && pw->pw_uid > 0 && pw->pw_gid > 0) {
237                         if (setgroups(0, NULL) != 0 ||
238                             setgid(pw->pw_gid) != 0 ||
239                             setuid(pw->pw_uid) != 0)
240                                 info(udev_ctx, "unable to drop privileges: %s\n\n", strerror(errno));
241                 }
242         }
243
244         if (probe_all) {
245                 volume_id_all_probers(all_probers, vid, offset, size, NULL);
246                 goto exit;
247         }
248
249         if (skip_raid)
250                 retval = volume_id_probe_filesystem(vid, offset, size);
251         else
252                 retval = volume_id_probe_all(vid, offset, size);
253         if (retval != 0) {
254                 fprintf(stderr, "unknown or non-unique volume type "
255                                 "(--probe-all lists possibly conflicting types)\n");
256                 rc = 4;
257                 goto exit;
258         }
259
260         if (!volume_id_get_label(vid, &label) ||
261             !volume_id_get_usage(vid, &usage) ||
262             !volume_id_get_type(vid, &type) ||
263             !volume_id_get_type_version(vid, &type_version) ||
264             !volume_id_get_uuid(vid, &uuid)) {
265                 rc = 4;
266                 goto exit;
267         }
268
269         udev_util_replace_whitespace(label, label_safe, sizeof(label_safe));
270         udev_util_replace_chars(label_safe, UDEV_ALLOWED_CHARS_INPUT);
271         volume_id_encode_string(label, label_enc, sizeof(label_enc));
272
273         udev_util_replace_whitespace(uuid, uuid_safe, sizeof(uuid_safe));
274         udev_util_replace_chars(uuid_safe, UDEV_ALLOWED_CHARS_INPUT);
275         volume_id_encode_string(uuid, uuid_enc, sizeof(uuid_enc));
276
277         volume_id_encode_string(type, type_enc, sizeof(type_enc));
278         volume_id_encode_string(type_version, type_version_enc, sizeof(type_version_enc));
279
280         switch (print) {
281         case PRINT_EXPORT:
282                 printf("ID_FS_USAGE=%s\n", usage);
283                 printf("ID_FS_TYPE=%s\n", type_enc);
284                 printf("ID_FS_VERSION=%s\n", type_version_enc);
285                 printf("ID_FS_UUID=%s\n", uuid_safe);
286                 printf("ID_FS_UUID_ENC=%s\n", uuid_enc);
287                 printf("ID_FS_LABEL=%s\n", label_safe);
288                 printf("ID_FS_LABEL_ENC=%s\n", label_enc);
289                 break;
290         case PRINT_TYPE:
291                 printf("%s\n", type);
292                 break;
293         case PRINT_LABEL:
294                 if (label_safe[0] == '\0' || strcmp(usage, "raid") == 0) {
295                         rc = 3;
296                         goto exit;
297                 }
298                 printf("%s\n", label_safe);
299                 break;
300         case PRINT_UUID:
301                 if (uuid_enc[0] == '\0' || strcmp(usage, "raid") == 0) {
302                         rc = 4;
303                         goto exit;
304                 }
305                 printf("%s\n", uuid_enc);
306                 break;
307         case PRINT_LABEL_RAW:
308                 if (label[0] == '\0' || strcmp(usage, "raid") == 0) {
309                         rc = 3;
310                         goto exit;
311                 }
312                 printf("%s\n", label);
313                 break;
314         }
315
316 exit:
317         if (vid != NULL)
318                 volume_id_close(vid);
319         udev_unref(udev_ctx);
320         logging_close();
321         return rc;
322 }