chiark / gitweb /
43d9516a19774250978d6c07af39fcff5a5d5978
[elogind.git] / extras / ata_id / ata_id.c
1 /*
2  * ata_id - reads product/serial number from ATA drives
3  *
4  * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
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.
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>
20 #include <string.h>
21 #include <errno.h>
22 #include <getopt.h>
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
29 #include "../../udev/udev.h"
30
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)
34 {
35         vsyslog(priority, format, args);
36 }
37
38 static void set_str(char *to, const char *from, size_t count)
39 {
40         size_t i, j, len;
41
42         /* strip trailing whitespace */
43         len = strnlen(from, count);
44         while (len && isspace(from[len-1]))
45                 len--;
46
47         /* strip leading whitespace */
48         i = 0;
49         while (isspace(from[i]) && (i < len))
50                 i++;
51
52         j = 0;
53         while (i < len) {
54                 /* substitute multiple whitespace */
55                 if (isspace(from[i])) {
56                         while (isspace(from[i]))
57                                 i++;
58                         to[j++] = '_';
59                 }
60                 /* skip chars */
61                 if (from[i] == '/') {
62                         i++;
63                         continue;
64                 }
65                 to[j++] = from[i++];
66         }
67         to[j] = '\0';
68 }
69
70 int main(int argc, char *argv[])
71 {
72         struct udev *udev;
73         struct hd_driveid id;
74         char model[41];
75         char serial[21];
76         char revision[9];
77         const char *node = NULL;
78         int export = 0;
79         int fd;
80         int rc = 0;
81         static const struct option options[] = {
82                 { "export", 0, NULL, 'x' },
83                 { "help", 0, NULL, 'h' },
84                 {}
85         };
86
87         udev = udev_new();
88         if (udev == NULL)
89                 goto exit;
90
91         logging_init("ata_id");
92         udev_set_log_fn(udev, log_fn);
93
94         while (1) {
95                 int option;
96
97                 option = getopt_long(argc, argv, "xh", options, NULL);
98                 if (option == -1)
99                         break;
100
101                 switch (option) {
102                 case 'x':
103                         export = 1;
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                 }
113         }
114
115         node = argv[optind];
116         if (node == NULL) {
117                 err(udev, "no node specified\n");
118                 rc = 1;
119                 goto exit;
120         }
121
122         fd = open(node, O_RDONLY|O_NONBLOCK);
123         if (fd < 0) {
124                 err(udev, "unable to open '%s'\n", node);
125                 rc = 1;
126                 goto exit;
127         }
128
129         if (ioctl(fd, HDIO_GET_IDENTITY, &id)) {
130                 if (errno == ENOTTY) {
131                         info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node);
132                         rc = 2;
133                 } else {
134                         err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node);
135                         rc = 3;
136                 }
137                 goto close;
138         }
139
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);
143
144         if (export) {
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                 }
167                 printf("ID_MODEL=%s\n", model);
168                 printf("ID_SERIAL=%s\n", serial);
169                 printf("ID_REVISION=%s\n", revision);
170                 printf("ID_BUS=ata\n");
171         } else {
172                 if (serial[0] != '\0')
173                         printf("%s_%s\n", model, serial);
174                 else
175                         printf("%s\n", model);
176         }
177
178 close:
179         close(fd);
180 exit:
181         udev_unref(udev);
182         logging_close();
183         return rc;
184 }