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