1/* 2 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> 3 * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation version 2 of the License. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 */ 19 20 21#include <stdlib.h> 22#include <stdio.h> 23#include <string.h> 24#include <stddef.h> 25#include <unistd.h> 26#include <fcntl.h> 27#include <string.h> 28#include <errno.h> 29#include <dirent.h> 30#include <sys/stat.h> 31#include <sys/types.h> 32 33#include "udev.h" 34 35 36static size_t devpath_to_db_path(const char *devpath, char *filename, size_t len) 37{ 38 size_t start; 39 40 /* add location of db files */ 41 strlcpy(filename, udev_root, len); 42 start = strlcat(filename, "/"DB_DIR"/", len); 43 strlcat(filename, devpath, len); 44 return path_encode(&filename[start], len - start); 45} 46 47/* reverse mapping from the device file name to the devpath */ 48static int name_index(const char *devpath, const char *name, int add) 49{ 50 char device[PATH_SIZE]; 51 char filename[PATH_SIZE * 2]; 52 size_t start; 53 int fd; 54 55 /* directory with device name */ 56 strlcpy(filename, udev_root, sizeof(filename)); 57 start = strlcat(filename, "/"DB_NAME_INDEX_DIR"/", sizeof(filename)); 58 strlcat(filename, name, sizeof(filename)); 59 path_encode(&filename[start], sizeof(filename) - start); 60 /* entry with the devpath */ 61 strlcpy(device, devpath, sizeof(device)); 62 path_encode(device, sizeof(device)); 63 strlcat(filename, "/", sizeof(filename)); 64 strlcat(filename, device, sizeof(filename)); 65 66 if (add) { 67 info("creating index: '%s'", filename); 68 create_path(filename); 69 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); 70 if (fd > 0) 71 close(fd); 72 } else { 73 info("removing index: '%s'", filename); 74 unlink(filename); 75 delete_path(filename); 76 } 77 return 0; 78} 79 80int udev_db_get_devices_by_name(const char *name, struct list_head *name_list) 81{ 82 char dirname[PATH_MAX]; 83 size_t start; 84 DIR *dir; 85 int rc = 0; 86 87 strlcpy(dirname, udev_root, sizeof(dirname)); 88 start = strlcat(dirname, "/"DB_NAME_INDEX_DIR"/", sizeof(dirname)); 89 strlcat(dirname, name, sizeof(dirname)); 90 path_encode(&dirname[start], sizeof(dirname) - start); 91 92 dir = opendir(dirname); 93 if (dir == NULL) { 94 info("no index directory '%s': %s", dirname, strerror(errno)); 95 rc = -1; 96 goto out; 97 } 98 99 info("found index directory '%s'", dirname); 100 while (1) { 101 struct dirent *ent; 102 char device[PATH_SIZE]; 103 104 ent = readdir(dir); 105 if (ent == NULL || ent->d_name[0] == '\0') 106 break; 107 if (ent->d_name[0] == '.') 108 continue; 109 110 strlcpy(device, ent->d_name, sizeof(device)); 111 path_decode(device); 112 name_list_add(name_list, device, 0); 113 rc++; 114 } 115 closedir(dir); 116out: 117 return rc; 118} 119 120int udev_db_add_device(struct udevice *udev) 121{ 122 char filename[PATH_SIZE]; 123 124 if (udev->test_run) 125 return 0; 126 127 devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename)); 128 create_path(filename); 129 unlink(filename); 130 131 /* 132 * don't waste tmpfs memory pages, if we don't have any data to store 133 * create fake db-file; store the node-name in a symlink target 134 */ 135 if (list_empty(&udev->symlink_list) && list_empty(&udev->env_list) && 136 !udev->partitions && !udev->ignore_remove) { 137 dbg("nothing interesting to store, create symlink"); 138 if (symlink(udev->name, filename) != 0) { 139 err("unable to create db link '%s': %s", filename, strerror(errno)); 140 return -1; 141 } 142 } else { 143 FILE *f; 144 struct name_entry *name_loop; 145 146 f = fopen(filename, "w"); 147 if (f == NULL) { 148 err("unable to create db file '%s': %s", filename, strerror(errno)); 149 return -1; 150 } 151 dbg("storing data for device '%s' in '%s'", udev->dev->devpath, filename); 152 153 fprintf(f, "N:%s\n", udev->name); 154 list_for_each_entry(name_loop, &udev->symlink_list, node) { 155 fprintf(f, "S:%s\n", name_loop->name); 156 /* add symlink-name to index */ 157 name_index(udev->dev->devpath, name_loop->name, 1); 158 } 159 fprintf(f, "M:%u:%u\n", major(udev->devt), minor(udev->devt)); 160 if (udev->link_priority != 0) 161 fprintf(f, "L:%u\n", udev->link_priority); 162 if (udev->partitions != 0) 163 fprintf(f, "A:%u\n", udev->partitions); 164 if (udev->ignore_remove) 165 fprintf(f, "R:%u\n", udev->ignore_remove); 166 list_for_each_entry(name_loop, &udev->env_list, node) 167 fprintf(f, "E:%s\n", name_loop->name); 168 fclose(f); 169 } 170 171 /* add name to index */ 172 name_index(udev->dev->devpath, udev->name, 1); 173 174 return 0; 175} 176 177int udev_db_get_device(struct udevice *udev, const char *devpath) 178{ 179 struct stat stats; 180 char filename[PATH_SIZE]; 181 char line[PATH_SIZE]; 182 unsigned int maj, min; 183 char *bufline; 184 char *buf; 185 size_t bufsize; 186 size_t cur; 187 size_t count; 188 189 sysfs_device_set_values(udev->dev, devpath, NULL, NULL); 190 devpath_to_db_path(devpath, filename, sizeof(filename)); 191 192 if (lstat(filename, &stats) != 0) { 193 info("no db file to read %s: %s", filename, strerror(errno)); 194 return -1; 195 } 196 if ((stats.st_mode & S_IFMT) == S_IFLNK) { 197 char target[NAME_SIZE]; 198 int target_len; 199 200 info("found a symlink as db file"); 201 target_len = readlink(filename, target, sizeof(target)); 202 if (target_len > 0) 203 target[target_len] = '\0'; 204 else { 205 info("error reading db link %s: %s", filename, strerror(errno)); 206 return -1; 207 } 208 dbg("db link points to '%s'", target); 209 strlcpy(udev->name, target, sizeof(udev->name)); 210 return 0; 211 } 212 213 if (file_map(filename, &buf, &bufsize) != 0) { 214 info("error reading db file %s: %s", filename, strerror(errno)); 215 return -1; 216 } 217 218 cur = 0; 219 while (cur < bufsize) { 220 count = buf_get_line(buf, bufsize, cur); 221 bufline = &buf[cur]; 222 cur += count+1; 223 224 switch(bufline[0]) { 225 case 'N': 226 if (count > sizeof(udev->name)) 227 count = sizeof(udev->name); 228 memcpy(udev->name, &bufline[2], count-2); 229 udev->name[count-2] = '\0'; 230 break; 231 case 'M': 232 if (count > sizeof(line)) 233 count = sizeof(line); 234 memcpy(line, &bufline[2], count-2); 235 line[count-2] = '\0'; 236 sscanf(line, "%u:%u", &maj, &min); 237 udev->devt = makedev(maj, min); 238 break; 239 case 'S': 240 if (count > sizeof(line)) 241 count = sizeof(line); 242 memcpy(line, &bufline[2], count-2); 243 line[count-2] = '\0'; 244 name_list_add(&udev->symlink_list, line, 0); 245 break; 246 case 'L': 247 if (count > sizeof(line)) 248 count = sizeof(line); 249 memcpy(line, &bufline[2], count-2); 250 line[count-2] = '\0'; 251 udev->link_priority = atoi(line); 252 break; 253 case 'A': 254 if (count > sizeof(line)) 255 count = sizeof(line); 256 memcpy(line, &bufline[2], count-2); 257 line[count-2] = '\0'; 258 udev->partitions = atoi(line); 259 break; 260 case 'R': 261 if (count > sizeof(line)) 262 count = sizeof(line); 263 memcpy(line, &bufline[2], count-2); 264 line[count-2] = '\0'; 265 udev->ignore_remove = atoi(line); 266 break; 267 case 'E': 268 if (count > sizeof(line)) 269 count = sizeof(line); 270 memcpy(line, &bufline[2], count-2); 271 line[count-2] = '\0'; 272 name_list_add(&udev->env_list, line, 0); 273 break; 274 } 275 } 276 file_unmap(buf, bufsize); 277 278 if (udev->name[0] == '\0') 279 return -1; 280 281 return 0; 282} 283 284int udev_db_delete_device(struct udevice *udev) 285{ 286 char filename[PATH_SIZE]; 287 struct name_entry *name_loop; 288 289 if (udev->test_run) 290 return 0; 291 292 devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename)); 293 unlink(filename); 294 295 name_index(udev->dev->devpath, udev->name, 0); 296 list_for_each_entry(name_loop, &udev->symlink_list, node) 297 name_index(udev->dev->devpath, name_loop->name, 0); 298 299 return 0; 300} 301 302int udev_db_get_all_entries(struct list_head *name_list) 303{ 304 char dbpath[PATH_MAX]; 305 DIR *dir; 306 307 strlcpy(dbpath, udev_root, sizeof(dbpath)); 308 strlcat(dbpath, "/"DB_DIR, sizeof(dbpath)); 309 dir = opendir(dbpath); 310 if (dir == NULL) { 311 info("no udev_db available '%s': %s", dbpath, strerror(errno)); 312 return -1; 313 } 314 315 while (1) { 316 struct dirent *ent; 317 char device[PATH_SIZE]; 318 319 ent = readdir(dir); 320 if (ent == NULL || ent->d_name[0] == '\0') 321 break; 322 if (ent->d_name[0] == '.') 323 continue; 324 325 strlcpy(device, ent->d_name, sizeof(device)); 326 path_decode(device); 327 name_list_add(name_list, device, 1); 328 dbg("added '%s'", device); 329 } 330 331 closedir(dir); 332 return 0; 333} 334