fsid - Add to tree but don't build
[dragonfly.git] / sbin / fsid / fsid.c
1 /*
2  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/stat.h>
35 #include <devattr.h>
36 #include <errno.h>
37 #include "fsid.h"
38
39 static struct fs_type fs_types[] = {
40         { "HAMMER",     hammer_probe,   hammer_volname  },
41         { "UFS",        ufs_probe,      ufs_volname     },
42         { NULL,         NULL,           NULL            }
43 };
44
45
46 static struct fsid_head fsid_list =
47                 TAILQ_HEAD_INITIALIZER(fsid_list);
48
49 static int
50 fsid_alias_exists(const char *dev)
51 {
52         struct fsid_entry *fsid;
53         int exists = 0;
54
55         if (TAILQ_EMPTY(&fsid_list))
56                 return 0;
57
58         TAILQ_FOREACH(fsid, &fsid_list, link) {
59                 if (strcmp(fsid->dev_path, dev) == 0) {
60                         exists = 1;
61                         break;
62                 }
63         }
64
65         return exists;
66 }
67
68 static int
69 fsid_check_create_alias(const char *dev)
70 {
71         struct fsid_entry *fsid;
72         char full_path[MAXPATHLEN];
73         char link_path[MAXPATHLEN];
74         char *volname;
75         int i;
76
77         if (fsid_alias_exists(dev))
78                 return EEXIST;
79
80         sprintf(full_path, "/dev/%s", dev);
81         for (i = 0; fs_types[i].fs_name != NULL; i++) {
82                 volname = fs_types[i].fs_volname(full_path);
83                 if (volname == NULL)
84                         continue;
85
86                 printf("Volume name for %s is %s\n", dev, volname);
87                 fsid = malloc(sizeof(struct fsid_entry));
88                 if (fsid == NULL)
89                         return ENOMEM;
90 #if 1
91                 sprintf(link_path, "/dev/vol-by-name/%s", volname);
92
93                 fsid->dev_path = strdup(dev);
94                 fsid->link_path = strdup(link_path);
95                 if ((fsid->dev_path == NULL) || (fsid->link_path == NULL)) {
96                         free(fsid);
97                         return ENOMEM;
98                 }
99
100                 mkdir("/dev/vol-by-name", 0755);
101                 symlink(full_path, link_path);
102
103                 TAILQ_INSERT_TAIL(&fsid_list, fsid, link);
104 #endif
105                 break;
106         }
107
108         return 0;
109 }
110
111 static int
112 fsid_check_remove_alias(const char *dev)
113 {
114         struct fsid_entry *fsid, *fsid2;
115
116         if (!fsid_alias_exists(dev))
117                 return 0;
118
119         TAILQ_FOREACH_MUTABLE(fsid, &fsid_list, link, fsid2) {
120                 if (strcmp(fsid->dev_path, dev) != 0)
121                         continue;
122
123                 TAILQ_REMOVE(&fsid_list, fsid, link);
124
125                 unlink(fsid->link_path);
126
127                 free(fsid->dev_path);
128                 free(fsid->link_path);
129                 free(fsid);
130         }
131
132         return 0;
133 }
134
135 static
136 void
137 usage(void)
138 {
139         fprintf(stderr, "usage: fsid [-d]\n");
140         exit(1);
141 }
142
143 int
144 main(int argc, char *argv[])
145 {
146         struct udev *udev;
147         struct udev_enumerate *udev_enum;
148         struct udev_list_entry *udev_le, *udev_le_first;
149         struct udev_monitor *udev_monitor;
150         struct udev_device *udev_dev;
151         int ch;
152 #if 0
153         prop_dictionary_t *dict;
154 #endif
155         int ret, daemon_flag = 0;
156         const char *prop, *dev_path;
157
158         while ((ch = getopt(argc, argv, "d")) != -1) {
159                 switch(ch) {
160                 case 'd':
161                         daemon_flag = 1;
162                         break;
163                 default:
164                         usage();
165                         /* NOT REACHED */
166                 }
167         }
168         argc -= optind;
169         argv += optind;
170
171         udev = udev_new();
172         if (udev == NULL)
173                 err(1, "udev_new");
174
175         udev_enum = udev_enumerate_new(udev);
176         if (udev_enum == NULL)
177                 err(1, "udev_enumerate_new");
178
179         ret = udev_enumerate_add_match_property(udev_enum, "subsystem", "disk");
180         if (ret != 0)
181                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
182 #if 1
183         ret = udev_enumerate_add_match_property(udev_enum, "alias", "0");
184         if (ret != 0)
185                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
186
187         ret = udev_enumerate_add_nomatch_property(udev_enum, "disk-type", "memory");
188         if (ret != 0)
189                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
190 #endif
191
192         ret = udev_enumerate_scan_devices(udev_enum);
193         if (ret != 0)
194                 err(1, "udev_enumerate_scan_device ret = %d", ret);
195
196         udev_le_first = udev_enumerate_get_list_entry(udev_enum);
197         if (udev_le_first == NULL)
198                 err(1, "udev_enumerate_get_list_entry error");
199
200         udev_list_entry_foreach(udev_le, udev_le_first) {
201                 udev_dev = udev_list_entry_get_device(udev_le);
202                 dev_path = udev_device_get_devnode(udev_dev);
203 #if 0
204                 dict = udev_device_get_dictionary(udev_dev);
205                 printf("xml of new device: %s\n", prop_dictionary_externalize(dict));
206 #endif
207                 fsid_check_create_alias(dev_path);
208         }
209
210         udev_enumerate_unref(udev_enum);
211
212         if (daemon_flag) {
213 #if 0
214                 if (daemon(0, 0) == -1)
215                         err(1, "daemon");
216 #endif
217
218                 udev_monitor = udev_monitor_new(udev);
219                 ret = udev_monitor_filter_add_match_property(udev_monitor, "subsystem", "disk");
220                 if (ret != 0)
221                         err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
222
223                 ret = udev_monitor_filter_add_match_property(udev_monitor, "alias", "0");
224                 if (ret != 0)
225                         err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
226
227                 ret = udev_monitor_filter_add_nomatch_property(udev_monitor, "disk-type", "memory");
228                 if (ret != 0)
229                         err(1, "udev_monitor_filter_add_nomatch_property, out, ret=%d\n", ret);
230
231                 ret = udev_monitor_enable_receiving(udev_monitor);
232                 if (ret != 0)
233                         err(1, "udev_monitor_enable_receiving ret = %d", ret);
234
235                 while ((udev_dev = udev_monitor_receive_device(udev_monitor))) {
236                         if (udev_dev == NULL)
237                                 err(1, "udev_monitor_receive_device failed");
238
239                         dev_path = udev_device_get_devnode(udev_dev);
240                         prop = udev_device_get_action(udev_dev);
241
242                         if (strcmp(prop, "attach") == 0)
243                                 fsid_check_create_alias(dev_path);
244                         else if (strcmp(prop, "detach") == 0)
245                                 fsid_check_remove_alias(dev_path);
246                 }
247
248                 udev_monitor_unref(udev_monitor);
249         }
250
251         udev_unref(udev);
252
253         return 0;
254 }
255