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