chiark / gitweb /
[PATCH] udev_volume_id: new version of 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 <string.h>
28 #include <ctype.h>
29 #include <sys/ioctl.h>
30
31 #include "../../libsysfs/sysfs/libsysfs.h"
32 #include "../../udev_utils.h"
33 #include "../../logging.h"
34 #include "volume_id/volume_id.h"
35 #include "volume_id/dasd/dasd.h"
36
37 #define BLKGETSIZE64 _IOR(0x12,114,size_t)
38
39 #ifdef LOG
40 void log_message(int level, const char *format, ...)
41 {
42         va_list args;
43
44         va_start(args, format);
45         vsyslog(level, format, args);
46         va_end(args);
47 }
48 #endif
49
50 static struct volume_id *open_classdev(struct sysfs_class_device *class_dev)
51 {
52         struct volume_id *vid;
53         struct sysfs_attribute *attr;
54         int major, minor;
55
56         attr = sysfs_get_classdev_attr(class_dev, "dev");
57
58         if (attr == NULL) {
59                 printf("error reading 'dev' attribute\n");
60                 return NULL;
61         }
62
63         if (sscanf(attr->value, "%u:%u", &major, &minor) != 2) {
64                 printf("error getting major/minor number\n");
65                 return NULL;
66         }
67
68         vid = volume_id_open_dev_t(makedev(major, minor));
69         if (vid == NULL) {
70                 printf("error open volume\n");
71                 return NULL;
72         }
73
74         return vid;
75 }
76
77 int main(int argc, char *argv[])
78 {
79         const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
80                             "       -t filesystem type\n"
81                             "       -l filesystem label\n"
82                             "       -u filesystem uuid\n"
83                             "       -d disk label from main device\n"
84                             "\n";
85         static const char short_options[] = "htlud";
86         char sysfs_mnt_path[SYSFS_PATH_MAX];
87         char dev_path[SYSFS_PATH_MAX];
88         struct sysfs_class_device *class_dev = NULL;
89         struct sysfs_class_device *class_dev_parent = NULL;
90         struct volume_id *vid = NULL;
91         char *devpath;
92         char probe = 'p';
93         char print = 'a';
94         static char name[VOLUME_ID_LABEL_SIZE];
95         int len, i, j;
96         unsigned long long size;
97         int rc = 1;
98
99         logging_init("udev_volume_id");
100
101         while (1) {
102                 int option;
103
104                 option = getopt(argc, argv, short_options);
105                 if (option == -1)
106                         break;
107
108                 switch (option) {
109                 case 't':
110                         print = 't';
111                         continue;
112                 case 'l':
113                         print = 'l';
114                         continue;
115                 case 'u':
116                         print = 'u';
117                         continue;
118                 case 'd':
119                         probe = 'd';
120                         continue;
121                 case 'h':
122                 case '?':
123                 default:
124                         printf(help);
125                         exit(1);
126                 }
127         }
128
129         devpath = getenv("DEVPATH");
130         if (devpath == NULL) {
131                 printf("error DEVPATH empty\n");
132                 goto exit;
133         }
134
135         if (sysfs_get_mnt_path(sysfs_mnt_path, SYSFS_PATH_MAX) != 0) {
136                 printf("error getting sysfs mount path\n");
137                 goto exit;
138         }
139
140         strfieldcpy(dev_path, sysfs_mnt_path);
141         strfieldcat(dev_path, devpath);
142
143         class_dev = sysfs_open_class_device_path(dev_path);
144         if (class_dev == NULL) {
145                 printf("error getting class device\n");
146                 goto exit;
147         }
148
149         switch(probe) {
150         case 'p' :
151                 /* open block device */
152                 vid = open_classdev(class_dev);
153                 if (vid == NULL)
154                         goto exit;
155
156                 if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0)
157                         size = 0;
158
159                 if (volume_id_probe_all(vid, 0, size) == 0)
160                         goto print;
161                 break;
162         case 'd' :
163                 /* if we are on a partition, open main block device instead */
164                 class_dev_parent = sysfs_get_classdev_parent(class_dev);
165                 if (class_dev_parent != NULL)
166                         vid = open_classdev(class_dev_parent);
167                 else
168                         vid = open_classdev(class_dev);
169                 if (vid == NULL)
170                         goto exit;
171
172                 if (probe_ibm_partition(vid) == 0)
173                         goto print;
174                 break;
175         }
176
177         printf("unknown volume type\n");
178         goto exit;
179
180
181 print:
182         len = strnlen(vid->label, VOLUME_ID_LABEL_SIZE);
183
184         /* remove trailing spaces */
185         while (len > 0 && isspace(vid->label[len-1]))
186                 len--;
187         name[len] = '\0';
188
189         /* substitute chars */
190         i = 0;
191         j = 0;
192         while (j < len) {
193                 switch(vid->label[j]) {
194                 case '/' :
195                         break;
196                 case ' ' :
197                         name[i++] = '_';
198                         break;
199                 default :
200                         name[i++] = vid->label[j];
201                 }
202                 j++;
203         }
204         name[i] = '\0';
205
206         switch (print) {
207         case 't':
208                 printf("%s\n", vid->type);
209                 break;
210         case 'l':
211                 if (name[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
212                         rc = 2;
213                         goto exit;
214                 }
215                 printf("%s\n", name);
216                 break;
217         case 'u':
218                 if (vid->uuid[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
219                         rc = 2;
220                         goto exit;
221                 }
222                 printf("%s\n", vid->uuid);
223                 break;
224         case 'a':
225                 printf("F:%s\n", vid->usage);
226                 printf("T:%s\n", vid->type);
227                 printf("V:%s\n", vid->type_version);
228                 printf("L:%s\n", vid->label);
229                 printf("N:%s\n", name);
230                 printf("U:%s\n", vid->uuid);
231         }
232         rc = 0;
233
234 exit:
235         if (class_dev != NULL)
236                 sysfs_close_class_device(class_dev);
237         if (vid != NULL)
238                 volume_id_close(vid);
239
240         logging_close();
241
242         exit(rc);
243 }