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 35 #include <sys/stat.h> 36 #include <devattr.h> 37 #include <errno.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