1/* 2 * edd_id - naming of BIOS disk devices via EDD 3 * 4 * Copyright (C) 2005 John Hull <John_Hull@Dell.com> 5 * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation version 2 of the License. 10 */ 11 12#ifndef _GNU_SOURCE 13#define _GNU_SOURCE 1 14#endif 15 16#include <stdio.h> 17#include <stdlib.h> 18#include <unistd.h> 19#include <fcntl.h> 20#include <ctype.h> 21#include <string.h> 22#include <errno.h> 23#include <dirent.h> 24#include <stdint.h> 25 26#include "../../udev.h" 27 28#ifdef USE_LOG 29void log_message(int priority, const char *format, ...) 30{ 31 va_list args; 32 static int udev_log = -1; 33 34 if (udev_log == -1) { 35 const char *value; 36 37 value = getenv("UDEV_LOG"); 38 if (value) 39 udev_log = log_priority(value); 40 else 41 udev_log = LOG_ERR; 42 } 43 44 if (priority > udev_log) 45 return; 46 47 va_start(args, format); 48 vsyslog(priority, format, args); 49 va_end(args); 50} 51#endif 52 53int main(int argc, char *argv[]) 54{ 55 const char *node = NULL; 56 int i; 57 int export = 0; 58 uint32_t disk_id; 59 uint16_t mbr_valid; 60 struct dirent *dent; 61 int disk_fd; 62 int sysfs_fd; 63 DIR *dir = NULL; 64 int rc = 1; 65 char match[NAME_MAX] = ""; 66 67 logging_init("edd_id"); 68 69 for (i = 1 ; i < argc; i++) { 70 char *arg = argv[i]; 71 72 if (strcmp(arg, "--export") == 0) { 73 export = 1; 74 } else 75 node = arg; 76 } 77 if (node == NULL) { 78 err("no node specified"); 79 fprintf(stderr, "no node specified\n"); 80 goto exit; 81 } 82 83 /* check for kernel support */ 84 dir = opendir("/sys/firmware/edd"); 85 if (dir == NULL) { 86 info("no kernel EDD support"); 87 fprintf(stderr, "no kernel EDD support\n"); 88 rc = 2; 89 goto exit; 90 } 91 92 disk_fd = open(node, O_RDONLY); 93 if (disk_fd < 0) { 94 info("unable to open '%s'", node); 95 fprintf(stderr, "unable to open '%s'\n", node); 96 rc = 3; 97 goto closedir; 98 } 99 100 /* check for valid MBR signature */ 101 if (lseek(disk_fd, 510, SEEK_SET) < 0) { 102 info("seek to MBR validity failed '%s'", node); 103 rc = 4; 104 goto close; 105 } 106 if (read(disk_fd, &mbr_valid, sizeof(mbr_valid)) != sizeof(mbr_valid)) { 107 info("read MBR validity failed '%s'", node); 108 rc = 5; 109 goto close; 110 } 111 if (mbr_valid != 0xAA55) { 112 fprintf(stderr, "no valid MBR signature '%s'\n", node); 113 info("no valid MBR signature '%s'", node); 114 rc=6; 115 goto close; 116 } 117 118 /* read EDD signature */ 119 if (lseek(disk_fd, 440, SEEK_SET) < 0) { 120 info("seek to signature failed '%s'", node); 121 rc = 7; 122 goto close; 123 } 124 if (read(disk_fd, &disk_id, sizeof(disk_id)) != sizeof(disk_id)) { 125 info("read signature failed '%s'", node); 126 rc = 8; 127 goto close; 128 } 129 /* all zero is invalid */ 130 info("read id 0x%08x from '%s'", disk_id, node); 131 if (disk_id == 0) { 132 fprintf(stderr, "no EDD signature '%s'\n", node); 133 info("'%s' signature is zero", node); 134 rc = 9; 135 goto close; 136 } 137 138 /* lookup signature in sysfs to determine the name */ 139 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { 140 char file[PATH_SIZE]; 141 char sysfs_id_buf[256]; 142 uint32_t sysfs_id; 143 ssize_t size; 144 145 if (dent->d_name[0] == '.') 146 continue; 147 148 snprintf(file, sizeof(file), "/sys/firmware/edd/%s/mbr_signature", dent->d_name); 149 file[sizeof(file)-1] = '\0'; 150 151 sysfs_fd = open(file, O_RDONLY); 152 if (sysfs_fd < 0) { 153 info("unable to open sysfs '%s'", file); 154 continue; 155 } 156 157 size = read(sysfs_fd, sysfs_id_buf, sizeof(sysfs_id_buf)-1); 158 close(sysfs_fd); 159 if (size <= 0) { 160 info("read sysfs '%s' failed", file); 161 continue; 162 } 163 sysfs_id_buf[size] = '\0'; 164 info("read '%s' from '%s'", sysfs_id_buf, file); 165 sysfs_id = strtoul(sysfs_id_buf, NULL, 16); 166 167 /* look for matching value, that appears only once */ 168 if (disk_id == sysfs_id) { 169 if (match[0] == '\0') { 170 /* store id */ 171 strlcpy(match, dent->d_name, sizeof(match)); 172 } else { 173 /* error, same signature for another device */ 174 info("'%s' does not have a unique signature", node); 175 fprintf(stderr, "'%s' does not have a unique signature\n", node); 176 rc = 10; 177 goto exit; 178 } 179 } 180 } 181 182 if (match[0] != '\0') { 183 if (export) 184 printf("ID_EDD=%s\n", match); 185 else 186 printf("%s\n", match); 187 rc = 0; 188 } 189 190close: 191 close(disk_fd); 192closedir: 193 closedir(dir); 194exit: 195 logging_close(); 196 return rc; 197} 198