cce409e9d5df52f7bc685f79bf11fdeb763fe41f
[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 <libfsid.h>
38 #include "fsid.h"
39
40 static struct fsid_head fsid_list =
41                 TAILQ_HEAD_INITIALIZER(fsid_list);
42
43 static int
44 fsid_alias_exists(const char *dev)
45 {
46         struct fsid_entry *fsid;
47         int exists = 0;
48
49         if (TAILQ_EMPTY(&fsid_list))
50                 return 0;
51
52         TAILQ_FOREACH(fsid, &fsid_list, link) {
53                 if (strcmp(fsid->dev_path, dev) == 0) {
54                         exists = 1;
55                         break;
56                 }
57         }
58
59         return exists;
60 }
61
62 static int
63 fsid_check_create_alias(const char *dev)
64 {
65         struct fsid_entry *fsid;
66         char full_path[MAXPATHLEN];
67         char link_path[MAXPATHLEN];
68         char *volname;
69
70         if (fsid_alias_exists(dev))
71                 return EEXIST;
72
73         sprintf(full_path, "/dev/%s", dev);
74         volname = fsid_volname_all(full_path);
75         if (volname == NULL)
76                 return 0;
77
78         printf("Volume name for %s is %s\n", dev, volname);
79         fsid = malloc(sizeof(struct fsid_entry));
80         if (fsid == NULL)
81                 return ENOMEM;
82 #if 1
83         sprintf(link_path, "/dev/vol-by-name/%s", volname);
84
85         fsid->dev_path = strdup(dev);
86         fsid->link_path = strdup(link_path);
87         if ((fsid->dev_path == NULL) || (fsid->link_path == NULL)) {
88                 free(fsid);
89                 return ENOMEM;
90         }
91
92         mkdir("/dev/vol-by-name", 0755);
93         symlink(full_path, link_path);
94
95         TAILQ_INSERT_TAIL(&fsid_list, fsid, link);
96 #endif
97
98         return 0;
99 }
100
101 static int
102 fsid_check_remove_alias(const char *dev)
103 {
104         struct fsid_entry *fsid, *fsid2;
105
106         if (!fsid_alias_exists(dev))
107                 return 0;
108
109         TAILQ_FOREACH_MUTABLE(fsid, &fsid_list, link, fsid2) {
110                 if (strcmp(fsid->dev_path, dev) != 0)
111                         continue;
112
113                 TAILQ_REMOVE(&fsid_list, fsid, link);
114
115                 unlink(fsid->link_path);
116
117                 free(fsid->dev_path);
118                 free(fsid->link_path);
119                 free(fsid);
120         }
121
122         return 0;
123 }
124
125 static
126 void
127 usage(void)
128 {
129         fprintf(stderr, "usage: fsid [-d]\n");
130         exit(1);
131 }
132
133 int
134 main(int argc, char *argv[])
135 {
136         struct udev *udev;
137         struct udev_enumerate *udev_enum;
138         struct udev_list_entry *udev_le, *udev_le_first;
139         struct udev_monitor *udev_monitor;
140         struct udev_device *udev_dev;
141         int ch;
142 #if 0
143         prop_dictionary_t *dict;
144 #endif
145         int ret, daemon_flag = 0;
146         const char *prop, *dev_path;
147
148         while ((ch = getopt(argc, argv, "d")) != -1) {
149                 switch(ch) {
150                 case 'd':
151                         daemon_flag = 1;
152                         break;
153                 default:
154                         usage();
155                         /* NOT REACHED */
156                 }
157         }
158         argc -= optind;
159         argv += optind;
160
161         udev = udev_new();
162         if (udev == NULL)
163                 err(1, "udev_new");
164
165         udev_enum = udev_enumerate_new(udev);
166         if (udev_enum == NULL)
167                 err(1, "udev_enumerate_new");
168
169         ret = udev_enumerate_add_match_property(udev_enum, "subsystem", "disk");
170         if (ret != 0)
171                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
172 #if 1
173         ret = udev_enumerate_add_match_property(udev_enum, "alias", "0");
174         if (ret != 0)
175                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
176
177         ret = udev_enumerate_add_nomatch_property(udev_enum, "disk-type", "memory");
178         if (ret != 0)
179                 err(1, "udev_enumerate_add_match_property, out, ret=%d\n", ret);
180 #endif
181
182         ret = udev_enumerate_scan_devices(udev_enum);
183         if (ret != 0)
184                 err(1, "udev_enumerate_scan_device ret = %d", ret);
185
186         udev_le_first = udev_enumerate_get_list_entry(udev_enum);
187         if (udev_le_first == NULL)
188                 err(1, "udev_enumerate_get_list_entry error");
189
190         udev_list_entry_foreach(udev_le, udev_le_first) {
191                 udev_dev = udev_list_entry_get_device(udev_le);
192                 dev_path = udev_device_get_devnode(udev_dev);
193 #if 0
194                 dict = udev_device_get_dictionary(udev_dev);
195                 printf("xml of new device: %s\n", prop_dictionary_externalize(dict));
196 #endif
197                 fsid_check_create_alias(dev_path);
198         }
199
200         udev_enumerate_unref(udev_enum);
201
202         if (daemon_flag) {
203 #if 0
204                 if (daemon(0, 0) == -1)
205                         err(1, "daemon");
206 #endif
207
208                 udev_monitor = udev_monitor_new(udev);
209                 ret = udev_monitor_filter_add_match_property(udev_monitor, "subsystem", "disk");
210                 if (ret != 0)
211                         err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
212
213                 ret = udev_monitor_filter_add_match_property(udev_monitor, "alias", "0");
214                 if (ret != 0)
215                         err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
216
217                 ret = udev_monitor_filter_add_nomatch_property(udev_monitor, "disk-type", "memory");
218                 if (ret != 0)
219                         err(1, "udev_monitor_filter_add_nomatch_property, out, ret=%d\n", ret);
220
221                 ret = udev_monitor_enable_receiving(udev_monitor);
222                 if (ret != 0)
223                         err(1, "udev_monitor_enable_receiving ret = %d", ret);
224
225                 while ((udev_dev = udev_monitor_receive_device(udev_monitor))) {
226                         if (udev_dev == NULL)
227                                 err(1, "udev_monitor_receive_device failed");
228
229                         dev_path = udev_device_get_devnode(udev_dev);
230                         prop = udev_device_get_action(udev_dev);
231
232                         if (strcmp(prop, "attach") == 0)
233                                 fsid_check_create_alias(dev_path);
234                         else if (strcmp(prop, "detach") == 0)
235                                 fsid_check_remove_alias(dev_path);
236                 }
237
238                 udev_monitor_unref(udev_monitor);
239         }
240
241         udev_unref(udev);
242
243         return 0;
244 }
245