xref: /dragonfly/sbin/fsid/fsid.c (revision 9348a738)
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 
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 
181 	ret = udev_enumerate_add_nomatch_property(udev_enum, "disk-type", "floppy");
182 
183 	ret = udev_enumerate_scan_devices(udev_enum);
184 	if (ret != 0)
185 		err(1, "udev_enumerate_scan_device ret = %d", ret);
186 
187 	udev_le_first = udev_enumerate_get_list_entry(udev_enum);
188 	if (udev_le_first == NULL)
189 		err(1, "udev_enumerate_get_list_entry error");
190 
191 	udev_list_entry_foreach(udev_le, udev_le_first) {
192 		udev_dev = udev_list_entry_get_device(udev_le);
193 		dev_path = udev_device_get_devnode(udev_dev);
194 #if 0
195 		dict = udev_device_get_dictionary(udev_dev);
196 		printf("xml of new device: %s\n", prop_dictionary_externalize(dict));
197 #endif
198 		fsid_check_create_alias(dev_path);
199 	}
200 
201 	udev_enumerate_unref(udev_enum);
202 
203 	if (daemon_flag) {
204 #if 0
205 		if (daemon(0, 0) == -1)
206 			err(1, "daemon");
207 #endif
208 
209 		udev_monitor = udev_monitor_new(udev);
210 		ret = udev_monitor_filter_add_match_property(udev_monitor, "subsystem", "disk");
211 		if (ret != 0)
212 			err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
213 
214 		ret = udev_monitor_filter_add_match_property(udev_monitor, "alias", "0");
215 		if (ret != 0)
216 			err(1, "udev_monitor_filter_add_match_property, out, ret=%d\n", ret);
217 
218 		ret = udev_monitor_filter_add_nomatch_property(udev_monitor, "disk-type", "memory");
219 		if (ret != 0)
220 			err(1, "udev_monitor_filter_add_nomatch_property, out, ret=%d\n", ret);
221 
222 		ret = udev_monitor_enable_receiving(udev_monitor);
223 		if (ret != 0)
224 			err(1, "udev_monitor_enable_receiving ret = %d", ret);
225 
226 		while ((udev_dev = udev_monitor_receive_device(udev_monitor))) {
227 			if (udev_dev == NULL)
228 				err(1, "udev_monitor_receive_device failed");
229 
230 			dev_path = udev_device_get_devnode(udev_dev);
231 			prop = udev_device_get_action(udev_dev);
232 
233 			if (strcmp(prop, "attach") == 0)
234 				fsid_check_create_alias(dev_path);
235 			else if (strcmp(prop, "detach") == 0)
236 				fsid_check_remove_alias(dev_path);
237 		}
238 
239 		udev_monitor_unref(udev_monitor);
240 	}
241 
242 	udev_unref(udev);
243 
244 	return 0;
245 }
246 
247