chiark / gitweb /
rule_generator: fix enumeration for write_cd_rules
[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 serial[21];
53         char revision[9];
54         const char *node = NULL;
55         int export = 0;
56         int fd;
57         int rc = 0;
58         static const struct option options[] = {
59                 { "export", no_argument, NULL, 'x' },
60                 { "help", no_argument, NULL, 'h' },
61                 {}
62         };
63
64         udev = udev_new();
65         if (udev == NULL)
66                 goto exit;
67
68         logging_init("ata_id");
69         udev_set_log_fn(udev, log_fn);
70
71         while (1) {
72                 int option;
73
74                 option = getopt_long(argc, argv, "xh", options, NULL);
75                 if (option == -1)
76                         break;
77
78                 switch (option) {
79                 case 'x':
80                         export = 1;
81                         break;
82                 case 'h':
83                         printf("Usage: ata_id [--export] [--help] <device>\n"
84                                "  --export    print values as environemt keys\n"
85                                "  --help      print this help text\n\n");
86                 default:
87                         rc = 1;
88                         goto exit;
89                 }
90         }
91
92         node = argv[optind];
93         if (node == NULL) {
94                 err(udev, "no node specified\n");
95                 rc = 1;
96                 goto exit;
97         }
98
99         fd = open(node, O_RDONLY|O_NONBLOCK);
100         if (fd < 0) {
101                 err(udev, "unable to open '%s'\n", node);
102                 rc = 1;
103                 goto exit;
104         }
105
106         if (ioctl(fd, HDIO_GET_IDENTITY, &id)) {
107                 if (errno == ENOTTY) {
108                         info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node);
109                         rc = 2;
110                 } else {
111                         err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node);
112                         rc = 3;
113                 }
114                 goto close;
115         }
116
117         udev_util_replace_whitespace((char *) id.model, model, 40);
118         udev_util_replace_chars(model, NULL);
119         udev_util_replace_whitespace((char *) id.serial_no, serial, 20);
120         udev_util_replace_chars(serial, NULL);
121         udev_util_replace_whitespace((char *) id.fw_rev, revision, 8);
122         udev_util_replace_chars(revision, NULL);
123
124         if (export) {
125                 if ((id.config >> 8) & 0x80) {
126                         /* This is an ATAPI device */
127                         switch ((id.config >> 8) & 0x1f) {
128                         case 0:
129                                 printf("ID_TYPE=cd\n");
130                                 break;
131                         case 1:
132                                 printf("ID_TYPE=tape\n");
133                                 break;
134                         case 5:
135                                 printf("ID_TYPE=cd\n");
136                                 break;
137                         case 7:
138                                 printf("ID_TYPE=optical\n");
139                                 break;
140                         default:
141                                 printf("ID_TYPE=generic\n");
142                                 break;
143                         }
144                 } else {
145                         printf("ID_TYPE=disk\n");
146                 }
147                 printf("ID_MODEL=%s\n", model);
148                 printf("ID_SERIAL=%s\n", serial);
149                 printf("ID_REVISION=%s\n", revision);
150                 printf("ID_BUS=ata\n");
151         } else {
152                 if (serial[0] != '\0')
153                         printf("%s_%s\n", model, serial);
154                 else
155                         printf("%s\n", model);
156         }
157
158 close:
159         close(fd);
160 exit:
161         udev_unref(udev);
162         logging_close();
163         return rc;
164 }