chiark / gitweb /
*_id: add model/vendor enc strings
[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
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <getopt.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <linux/types.h>
36 #include <linux/hdreg.h>
37
38 #include "../../udev/udev.h"
39
40 static void log_fn(struct udev *udev, int priority,
41                    const char *file, int line, const char *fn,
42                    const char *format, va_list args)
43 {
44         vsyslog(priority, format, args);
45 }
46
47 int main(int argc, char *argv[])
48 {
49         struct udev *udev;
50         struct hd_driveid id;
51         char model[41];
52         char model_enc[256];
53         char serial[21];
54         char revision[9];
55         const char *node = NULL;
56         int export = 0;
57         int fd;
58         int rc = 0;
59         static const struct option options[] = {
60                 { "export", no_argument, NULL, 'x' },
61                 { "help", no_argument, NULL, 'h' },
62                 {}
63         };
64
65         udev = udev_new();
66         if (udev == NULL)
67                 goto exit;
68
69         logging_init("ata_id");
70         udev_set_log_fn(udev, log_fn);
71
72         while (1) {
73                 int option;
74
75                 option = getopt_long(argc, argv, "xh", options, NULL);
76                 if (option == -1)
77                         break;
78
79                 switch (option) {
80                 case 'x':
81                         export = 1;
82                         break;
83                 case 'h':
84                         printf("Usage: ata_id [--export] [--help] <device>\n"
85                                "  --export    print values as environment keys\n"
86                                "  --help      print this help text\n\n");
87                 default:
88                         rc = 1;
89                         goto exit;
90                 }
91         }
92
93         node = argv[optind];
94         if (node == NULL) {
95                 err(udev, "no node specified\n");
96                 rc = 1;
97                 goto exit;
98         }
99
100         fd = open(node, O_RDONLY|O_NONBLOCK);
101         if (fd < 0) {
102                 err(udev, "unable to open '%s'\n", node);
103                 rc = 1;
104                 goto exit;
105         }
106
107         if (ioctl(fd, HDIO_GET_IDENTITY, &id)) {
108                 if (errno == ENOTTY) {
109                         info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node);
110                         rc = 2;
111                 } else {
112                         err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node);
113                         rc = 3;
114                 }
115                 goto close;
116         }
117
118         memcpy (model, id.model, 40);
119         model[40] = '\0';
120         udev_util_encode_string(model, model_enc, sizeof(model_enc));
121         udev_util_replace_whitespace((char *) id.model, model, 40);
122         udev_util_replace_chars(model, NULL);
123         udev_util_replace_whitespace((char *) id.serial_no, serial, 20);
124         udev_util_replace_chars(serial, NULL);
125         udev_util_replace_whitespace((char *) id.fw_rev, revision, 8);
126         udev_util_replace_chars(revision, NULL);
127
128         if (export) {
129                 if ((id.config >> 8) & 0x80) {
130                         /* This is an ATAPI device */
131                         switch ((id.config >> 8) & 0x1f) {
132                         case 0:
133                                 printf("ID_TYPE=cd\n");
134                                 break;
135                         case 1:
136                                 printf("ID_TYPE=tape\n");
137                                 break;
138                         case 5:
139                                 printf("ID_TYPE=cd\n");
140                                 break;
141                         case 7:
142                                 printf("ID_TYPE=optical\n");
143                                 break;
144                         default:
145                                 printf("ID_TYPE=generic\n");
146                                 break;
147                         }
148                 } else {
149                         printf("ID_TYPE=disk\n");
150                 }
151                 printf("ID_MODEL=%s\n", model);
152                 printf("ID_MODEL_ENC=%s\n", model_enc);
153                 printf("ID_SERIAL=%s\n", serial);
154                 printf("ID_REVISION=%s\n", revision);
155                 printf("ID_BUS=ata\n");
156         } else {
157                 if (serial[0] != '\0')
158                         printf("%s_%s\n", model, serial);
159                 else
160                         printf("%s\n", model);
161         }
162
163 close:
164         close(fd);
165 exit:
166         udev_unref(udev);
167         logging_close();
168         return rc;
169 }