]>
Commit | Line | Data |
---|---|---|
670e4705 KS |
1 | /* |
2 | * ata_id - reads product/serial number from ATA drives | |
3 | * | |
7d563a17 | 4 | * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org> |
670e4705 | 5 | * |
2321ba6f KS |
6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation version 2 of the License. | |
670e4705 KS |
9 | */ |
10 | ||
11 | #ifndef _GNU_SOURCE | |
12 | #define _GNU_SOURCE 1 | |
13 | #endif | |
14 | ||
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <unistd.h> | |
18 | #include <fcntl.h> | |
19 | #include <ctype.h> | |
1aa1e248 | 20 | #include <string.h> |
670e4705 | 21 | #include <errno.h> |
4fa3d99d | 22 | #include <getopt.h> |
670e4705 KS |
23 | #include <sys/ioctl.h> |
24 | #include <sys/types.h> | |
25 | #include <sys/stat.h> | |
26 | #include <linux/types.h> | |
27 | #include <linux/hdreg.h> | |
28 | ||
01618658 | 29 | #include "../../udev/udev.h" |
670e4705 | 30 | |
7d563a17 KS |
31 | static void log_fn(struct udev *udev, int priority, |
32 | const char *file, int line, const char *fn, | |
33 | const char *format, va_list args) | |
670e4705 | 34 | { |
670e4705 | 35 | vsyslog(priority, format, args); |
670e4705 | 36 | } |
670e4705 | 37 | |
70721db6 | 38 | static void set_str(char *to, const char *from, size_t count) |
670e4705 | 39 | { |
70721db6 | 40 | size_t i, j, len; |
670e4705 | 41 | |
aaff09a3 | 42 | /* strip trailing whitespace */ |
670e4705 | 43 | len = strnlen(from, count); |
c907c823 | 44 | while (len && isspace(from[len-1])) |
670e4705 KS |
45 | len--; |
46 | ||
aaff09a3 | 47 | /* strip leading whitespace */ |
670e4705 KS |
48 | i = 0; |
49 | while (isspace(from[i]) && (i < len)) | |
50 | i++; | |
51 | ||
52 | j = 0; | |
53 | while (i < len) { | |
aaff09a3 KS |
54 | /* substitute multiple whitespace */ |
55 | if (isspace(from[i])) { | |
56 | while (isspace(from[i])) | |
57 | i++; | |
670e4705 | 58 | to[j++] = '_'; |
670e4705 | 59 | } |
aaff09a3 KS |
60 | /* skip chars */ |
61 | if (from[i] == '/') { | |
62 | i++; | |
63 | continue; | |
64 | } | |
65 | to[j++] = from[i++]; | |
670e4705 KS |
66 | } |
67 | to[j] = '\0'; | |
68 | } | |
69 | ||
70 | int main(int argc, char *argv[]) | |
71 | { | |
7d563a17 | 72 | struct udev *udev; |
670e4705 KS |
73 | struct hd_driveid id; |
74 | char model[41]; | |
75 | char serial[21]; | |
76 | char revision[9]; | |
77 | const char *node = NULL; | |
670e4705 KS |
78 | int export = 0; |
79 | int fd; | |
80 | int rc = 0; | |
4fa3d99d KS |
81 | static const struct option options[] = { |
82 | { "export", 0, NULL, 'x' }, | |
83 | { "help", 0, NULL, 'h' }, | |
84 | {} | |
85 | }; | |
670e4705 | 86 | |
7d563a17 KS |
87 | udev = udev_new(); |
88 | if (udev == NULL) | |
89 | goto exit; | |
90 | ||
5f84d726 | 91 | logging_init("ata_id"); |
7d563a17 | 92 | udev_set_log_fn(udev, log_fn); |
5f84d726 | 93 | |
4fa3d99d KS |
94 | while (1) { |
95 | int option; | |
670e4705 | 96 | |
4fa3d99d KS |
97 | option = getopt_long(argc, argv, "xh", options, NULL); |
98 | if (option == -1) | |
99 | break; | |
100 | ||
101 | switch (option) { | |
102 | case 'x': | |
670e4705 | 103 | export = 1; |
4fa3d99d KS |
104 | break; |
105 | case 'h': | |
106 | printf("Usage: ata_id [--export] [--help] <device>\n" | |
107 | " --export print values as environemt keys\n" | |
108 | " --help print this help text\n\n"); | |
109 | default: | |
110 | rc = 1; | |
111 | goto exit; | |
112 | } | |
670e4705 | 113 | } |
4fa3d99d KS |
114 | |
115 | node = argv[optind]; | |
116 | if (node == NULL) { | |
7d563a17 | 117 | err(udev, "no node specified\n"); |
670e4705 KS |
118 | rc = 1; |
119 | goto exit; | |
120 | } | |
121 | ||
3515c0ad | 122 | fd = open(node, O_RDONLY|O_NONBLOCK); |
670e4705 | 123 | if (fd < 0) { |
7d563a17 | 124 | err(udev, "unable to open '%s'\n", node); |
670e4705 KS |
125 | rc = 1; |
126 | goto exit; | |
127 | } | |
128 | ||
129 | if (ioctl(fd, HDIO_GET_IDENTITY, &id)) { | |
cfdea0f6 | 130 | if (errno == ENOTTY) { |
7d563a17 | 131 | info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node); |
cfdea0f6 MS |
132 | rc = 2; |
133 | } else { | |
7d563a17 | 134 | err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node); |
cfdea0f6 MS |
135 | rc = 3; |
136 | } | |
670e4705 KS |
137 | goto close; |
138 | } | |
139 | ||
70721db6 KS |
140 | set_str(model, (char *) id.model, 40); |
141 | set_str(serial, (char *) id.serial_no, 20); | |
142 | set_str(revision, (char *) id.fw_rev, 8); | |
670e4705 KS |
143 | |
144 | if (export) { | |
aaff09a3 KS |
145 | if ((id.config >> 8) & 0x80) { |
146 | /* This is an ATAPI device */ | |
147 | switch ((id.config >> 8) & 0x1f) { | |
148 | case 0: | |
149 | printf("ID_TYPE=cd\n"); | |
150 | break; | |
151 | case 1: | |
152 | printf("ID_TYPE=tape\n"); | |
153 | break; | |
154 | case 5: | |
155 | printf("ID_TYPE=cd\n"); | |
156 | break; | |
157 | case 7: | |
158 | printf("ID_TYPE=optical\n"); | |
159 | break; | |
160 | default: | |
161 | printf("ID_TYPE=generic\n"); | |
162 | break; | |
163 | } | |
164 | } else { | |
165 | printf("ID_TYPE=disk\n"); | |
166 | } | |
670e4705 KS |
167 | printf("ID_MODEL=%s\n", model); |
168 | printf("ID_SERIAL=%s\n", serial); | |
169 | printf("ID_REVISION=%s\n", revision); | |
46f01c6d | 170 | printf("ID_BUS=ata\n"); |
e03bce63 KS |
171 | } else { |
172 | if (serial[0] != '\0') | |
173 | printf("%s_%s\n", model, serial); | |
174 | else | |
175 | printf("%s\n", model); | |
176 | } | |
670e4705 KS |
177 | |
178 | close: | |
179 | close(fd); | |
180 | exit: | |
7d563a17 | 181 | udev_unref(udev); |
670e4705 KS |
182 | logging_close(); |
183 | return rc; | |
184 | } |