chiark / gitweb /
[PATCH] update udev_volume_id
[elogind.git] / extras / volume_id / udev_volume_id.c
1 /*
2  * udev_volume_id - udev callout to read filesystem label and uuid
3  *
4  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      sample udev rule for creation of a symlink with the filsystem uuid:
7  *      KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -u", SYMLINK="%c"
8  *
9  *      This program is free software; you can redistribute it and/or modify it
10  *      under the terms of the GNU General Public License as published by the
11  *      Free Software Foundation version 2 of the License.
12  * 
13  *      This program is distributed in the hope that it will be useful, but
14  *      WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *      General Public License for more details.
17  * 
18  *      You should have received a copy of the GNU General Public License along
19  *      with this program; if not, write to the Free Software Foundation, Inc.,
20  *      675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <linux/fs.h>
29 #include <sys/ioctl.h>
30
31 #include "../../libsysfs/sysfs/libsysfs.h"
32 #include "../../udev_lib.h"
33 #include "../../logging.h"
34 #include "volume_id.h"
35 #include "dasdlabel.h"
36
37 #ifdef LOG
38 unsigned char logname[LOGNAME_SIZE];
39 void log_message(int level, const char *format, ...)
40 {
41         va_list args;
42
43         va_start(args, format);
44         vsyslog(level, format, args);
45         va_end(args);
46 }
47 #endif
48
49 static struct volume_id *open_classdev(struct sysfs_class_device *class_dev)
50 {
51         struct volume_id *vid;
52         struct sysfs_attribute *attr;
53         int major, minor;
54
55         attr = sysfs_get_classdev_attr(class_dev, "dev");
56
57         if (attr == NULL) {
58                 printf("error reading 'dev' attribute\n");
59                 return NULL;
60         }
61
62         if (sscanf(attr->value, "%u:%u", &major, &minor) != 2) {
63                 printf("error getting major/minor number\n");
64                 return NULL;
65         }
66
67         vid = volume_id_open_dev_t(makedev(major, minor));
68         if (vid == NULL) {
69                 printf("error open volume\n");
70                 return NULL;
71         }
72
73         return vid;
74 }
75
76 static unsigned long long get_size(struct volume_id *vid)
77 {
78         unsigned long long size;
79
80         if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0)
81                 size = 0;
82
83         return size;
84 }
85
86 static char *usage_id_name(enum volume_id_usage usage)
87 {
88         switch(usage) {
89         case VOLUME_ID_UNUSED:
90                 return "unused";
91         case VOLUME_ID_UNPROBED:
92                 return "unprobed";
93         case VOLUME_ID_OTHER:
94                 return "other";
95         case VOLUME_ID_PARTITIONTABLE:
96                 return "partitiontable";
97         case VOLUME_ID_FILESYSTEM:
98                 return "filesystem";
99         case VOLUME_ID_RAID:
100                 return "raid";
101         default:
102                 return "unknown type_id";
103         }
104 }
105
106 int main(int argc, char *argv[])
107 {
108         const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
109                             "       -t filesystem type\n"
110                             "       -l filesystem label\n"
111                             "       -u filesystem uuid\n"
112                             "       -d disk label from main device\n"
113                             "\n";
114         static const char short_options[] = "htlud";
115         char sysfs_path[SYSFS_PATH_MAX];
116         char dev_path[SYSFS_PATH_MAX];
117         struct sysfs_class_device *class_dev = NULL;
118         struct sysfs_class_device *class_dev_parent = NULL;
119         struct volume_id *vid = NULL;
120         char *devpath;
121         char probe = 'p';
122         char print = 'a';
123         char dasd_label[7];
124         static char name[VOLUME_ID_LABEL_SIZE];
125         int len, i, j;
126         unsigned long long size;
127         int rc = 1;
128
129         while (1) {
130                 int option;
131
132                 option = getopt(argc, argv, short_options);
133                 if (option == -1)
134                         break;
135
136                 switch (option) {
137                 case 't':
138                         print = 't';
139                         continue;
140                 case 'l':
141                         print = 'l';
142                         continue;
143                 case 'u':
144                         print = 'u';
145                         continue;
146                 case 'd':
147                         probe = 'd';
148                         continue;
149                 case 'h':
150                 case '?':
151                 default:
152                         printf(help);
153                         exit(1);
154                 }
155         }
156
157         devpath = getenv("DEVPATH");
158         if (devpath == NULL) {
159                 printf("error DEVPATH empty\n");
160                 goto exit;
161         }
162
163         if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
164                 printf("error getting sysfs mount path\n");
165                 goto exit;
166         }
167
168         strfieldcpy(dev_path, sysfs_path);
169         strfieldcat(dev_path, devpath);
170
171         class_dev = sysfs_open_class_device_path(dev_path);
172         if (class_dev == NULL) {
173                 printf("error getting class device\n");
174                 goto exit;
175         }
176
177         switch(probe) {
178         case 'p' :
179                 /* open block device */
180                 vid = open_classdev(class_dev);
181                 if (vid == NULL)
182                         goto exit;
183
184                 size = get_size(vid);
185
186                 if (volume_id_probe(vid, VOLUME_ID_ALL, 0, size) == 0)
187                         goto print;
188                 break;
189         case 'd' :
190                 /* if we are on a partition, open main block device instead */
191                 class_dev_parent = sysfs_get_classdev_parent(class_dev);
192                 if (class_dev_parent != NULL)
193                         vid = open_classdev(class_dev_parent);
194                 else
195                         vid = open_classdev(class_dev_parent);
196                 if (vid == NULL)
197                         goto exit;
198
199                 if (probe_ibm_partition(vid->fd, dasd_label) == 0) {
200                         vid->type = "dasd";
201                         strncpy(vid->label, dasd_label, 6);
202                         vid->label[6] = '\0';
203                         goto print;
204                 }
205                 break;
206         }
207
208         printf("unknown volume type\n");
209         goto exit;
210
211
212 print:
213         len = strnlen(vid->label, VOLUME_ID_LABEL_SIZE);
214
215         /* remove trailing spaces */
216         while (len > 0 && isspace(vid->label[len-1]))
217                 len--;
218         name[len] = '\0';
219
220         /* substitute chars */
221         i = 0;
222         j = 0;
223         while (j < len) {
224                 switch(vid->label[j]) {
225                 case '/' :
226                         break;
227                 case ' ' :
228                         name[i++] = '_';
229                         break;
230                 default :
231                         name[i++] = vid->label[j];
232                 }
233                 j++;
234         }
235         name[i] = '\0';
236
237         switch (print) {
238         case 't':
239                 printf("%s\n", vid->type);
240                 break;
241         case 'l':
242                 if (name[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
243                         rc = 2;
244                         goto exit;
245                 }
246                 printf("%s\n", name);
247                 break;
248         case 'u':
249                 if (vid->uuid[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
250                         rc = 2;
251                         goto exit;
252                 }
253                 printf("%s\n", vid->uuid);
254                 break;
255         case 'a':
256                 printf("F:%s\n", usage_id_name(vid->usage_id));
257                 printf("T:%s\n", vid->type);
258                 printf("V:%s\n", vid->type_version);
259                 printf("L:%s\n", vid->label);
260                 printf("N:%s\n", name);
261                 printf("U:%s\n", vid->uuid);
262         }
263         rc = 0;
264
265 exit:
266         if (class_dev != NULL)
267                 sysfs_close_class_device(class_dev);
268         if (vid != NULL)
269                 volume_id_close(vid);
270
271         exit(rc);
272 }