chiark / gitweb /
usb_id: use libudev
[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 static void set_str(char *to, const char *from, size_t count)
48 {
49         size_t i, j, len;
50
51         /* strip trailing whitespace */
52         len = strnlen(from, count);
53         while (len && isspace(from[len-1]))
54                 len--;
55
56         /* strip leading whitespace */
57         i = 0;
58         while (isspace(from[i]) && (i < len))
59                 i++;
60
61         j = 0;
62         while (i < len) {
63                 /* substitute multiple whitespace */
64                 if (isspace(from[i])) {
65                         while (isspace(from[i]))
66                                 i++;
67                         to[j++] = '_';
68                 }
69                 /* skip chars */
70                 if (from[i] == '/') {
71                         i++;
72                         continue;
73                 }
74                 to[j++] = from[i++];
75         }
76         to[j] = '\0';
77 }
78
79 int main(int argc, char *argv[])
80 {
81         struct udev *udev;
82         struct hd_driveid id;
83         char model[41];
84         char serial[21];
85         char revision[9];
86         const char *node = NULL;
87         int export = 0;
88         int fd;
89         int rc = 0;
90         static const struct option options[] = {
91                 { "export", no_argument, NULL, 'x' },
92                 { "help", no_argument, NULL, 'h' },
93                 {}
94         };
95
96         udev = udev_new();
97         if (udev == NULL)
98                 goto exit;
99
100         logging_init("ata_id");
101         udev_set_log_fn(udev, log_fn);
102
103         while (1) {
104                 int option;
105
106                 option = getopt_long(argc, argv, "xh", options, NULL);
107                 if (option == -1)
108                         break;
109
110                 switch (option) {
111                 case 'x':
112                         export = 1;
113                         break;
114                 case 'h':
115                         printf("Usage: ata_id [--export] [--help] <device>\n"
116                                "  --export    print values as environemt keys\n"
117                                "  --help      print this help text\n\n");
118                 default:
119                         rc = 1;
120                         goto exit;
121                 }
122         }
123
124         node = argv[optind];
125         if (node == NULL) {
126                 err(udev, "no node specified\n");
127                 rc = 1;
128                 goto exit;
129         }
130
131         fd = open(node, O_RDONLY|O_NONBLOCK);
132         if (fd < 0) {
133                 err(udev, "unable to open '%s'\n", node);
134                 rc = 1;
135                 goto exit;
136         }
137
138         if (ioctl(fd, HDIO_GET_IDENTITY, &id)) {
139                 if (errno == ENOTTY) {
140                         info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node);
141                         rc = 2;
142                 } else {
143                         err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node);
144                         rc = 3;
145                 }
146                 goto close;
147         }
148
149         set_str(model, (char *) id.model, 40);
150         set_str(serial, (char *) id.serial_no, 20);
151         set_str(revision, (char *) id.fw_rev, 8);
152
153         if (export) {
154                 if ((id.config >> 8) & 0x80) {
155                         /* This is an ATAPI device */
156                         switch ((id.config >> 8) & 0x1f) {
157                         case 0:
158                                 printf("ID_TYPE=cd\n");
159                                 break;
160                         case 1:
161                                 printf("ID_TYPE=tape\n");
162                                 break;
163                         case 5:
164                                 printf("ID_TYPE=cd\n");
165                                 break;
166                         case 7:
167                                 printf("ID_TYPE=optical\n");
168                                 break;
169                         default:
170                                 printf("ID_TYPE=generic\n");
171                                 break;
172                         }
173                 } else {
174                         printf("ID_TYPE=disk\n");
175                 }
176                 printf("ID_MODEL=%s\n", model);
177                 printf("ID_SERIAL=%s\n", serial);
178                 printf("ID_REVISION=%s\n", revision);
179                 printf("ID_BUS=ata\n");
180         } else {
181                 if (serial[0] != '\0')
182                         printf("%s_%s\n", model, serial);
183                 else
184                         printf("%s\n", model);
185         }
186
187 close:
188         close(fd);
189 exit:
190         udev_unref(udev);
191         logging_close();
192         return rc;
193 }