1 /*
2 * Copyright (c) 2006-2021 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <getopt.h>
16 #include <ctype.h>
17 #include <errno.h>
18
19 #include "sg_lib.h"
20
21 /* A utility program for the Linux OS SCSI subsystem.
22 *
23 * This program takes a asc_ascq.txt file from www.t10.org and
24 * checks it against the additional sense codes held in the
25 * sg_lib.c file.
26 * The online version of the asc_ascq codes can be found at:
27 * https://www.t10.org/lists/asc-num.txt
28 */
29
30 static const char * version_str = "1.09 20210226";
31
32
33 #define MAX_LINE_LEN 1024
34
35
36 static struct option long_options[] = {
37 {"help", 0, 0, 'h'},
38 {"verbose", 0, 0, 'v'},
39 {"version", 0, 0, 'V'},
40 {0, 0, 0, 0},
41 };
42
usage()43 static void usage()
44 {
45 fprintf(stderr, "Usage: "
46 "sg_chk_asc [--help] [--offset=POS] [--verbose] [--version]\n"
47 " <asc_ascq_file>\n"
48 " where:\n"
49 " --help|-h print out usage message\n"
50 " --offset=POS|-o POS line position in file where "
51 "text starts\n"
52 " origin 0 (def: 24 (was 25))\n"
53 " --verbose|-v increase verbosity\n"
54 " --version|-V print version string and exit\n\n"
55 "Checks asc/ascq codes in <asc_ascq_file> against the sg3_utils "
56 "library.\nThe additional sense codes (asc_ascq) can be found "
57 "at\nwww.t10.org/lists/asc-num.txt .\n"
58 );
59
60 }
61
main(int argc,char * argv[])62 int main(int argc, char * argv[])
63 {
64 int k, j, res, c, num, len;
65 unsigned int asc, ascq;
66 FILE * fp;
67 int offset = 24;
68 int verbose = 0;
69 char file_name[256];
70 char line[MAX_LINE_LEN];
71 char b[MAX_LINE_LEN];
72 char bb[MAX_LINE_LEN];
73 char * cp;
74 int ret = 1;
75
76 memset(file_name, 0, sizeof file_name);
77 memset(line, 0, sizeof file_name);
78 while (1) {
79 int option_index = 0;
80
81 c = getopt_long(argc, argv, "ho:vV", long_options,
82 &option_index);
83 if (c == -1)
84 break;
85
86 switch (c) {
87 case 'h':
88 case '?':
89 usage();
90 return 0;
91 case 'o':
92 offset = sg_get_num(optarg);
93 if (offset < 0) {
94 fprintf(stderr, "bad argument to --offset\n");
95 return 1;
96 }
97 break;
98 case 'v':
99 ++verbose;
100 break;
101 case 'V':
102 fprintf(stderr, "version: %s\n", version_str);
103 return 0;
104 default:
105 fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
106 usage();
107 return 1;
108 }
109 }
110 if (optind < argc) {
111 if ('\0' == file_name[0]) {
112 strncpy(file_name, argv[optind], sizeof(file_name) - 1);
113 file_name[sizeof(file_name) - 1] = '\0';
114 ++optind;
115 }
116 if (optind < argc) {
117 for (; optind < argc; ++optind)
118 fprintf(stderr, "Unexpected extra argument: %s\n",
119 argv[optind]);
120 usage();
121 return 1;
122 }
123 }
124
125 if (0 == file_name[0]) {
126 fprintf(stderr, "missing file name!\n");
127 usage();
128 return 1;
129 }
130 fp = fopen(file_name, "r");
131 if (NULL == fp) {
132 fprintf(stderr, "open error: %s: %s\n", file_name,
133 safe_strerror(errno));
134 return 1;
135 }
136 for (k = 0; (cp = fgets(line, sizeof(line) - 1, fp)); ++k) {
137 len = strlen(line);
138 if (len < 1)
139 continue;
140 if (! isdigit(line[0]))
141 continue;
142 num = sscanf(line, "%xh/%xh", &asc, &ascq);
143 if (1 == num)
144 ascq = 999;
145 if (num < 1) {
146 if (verbose)
147 fprintf(stderr, "Badly formed line number %d (num=%d)\n",
148 k + 1, num);
149 continue;
150 }
151 if (len < 26)
152 continue;
153 #if 0
154 strncpy(b , line, sizeof(b) - 1);
155 b[sizeof(b) - 1] = '\0';
156 num = strlen(b);
157 if (0xd == b[num - 2]) {
158 b[num - 2] = '\0';
159 b[num - 1] = '\0';
160 }
161 printf("\"%s\",\n", b);
162 #endif
163 strncpy(b , line + offset, sizeof(b) - 1);
164 b[sizeof(b) - 1] = '\0';
165 num = strlen(b);
166 if (0xd == b[num - 2])
167 b[num - 2] = '\0';
168 b[num - 1] = '\0';
169 num = strlen(b);
170 for (j = 0; j < num; ++j)
171 b[j] = toupper(b[j]);
172
173 bb[0] = '\0';
174 if (ascq < 999) {
175 cp = sg_get_asc_ascq_str(asc, ascq, sizeof(bb) - 1, bb);
176 if (NULL == cp) {
177 fprintf(stderr, "no entry for %x,%x : %s\n", asc, ascq, b);
178 continue;
179 }
180 num = strlen(cp);
181 // fprintf(stderr, "file: asc=%x acsq=%x strlen=%d %s\n", asc, ascq, num,
182 // cp);
183 // if (num < 20)
184 // continue;
185 if ((num > 6) &&
186 ((0 == memcmp("ASC", cp, 3)) ||
187 (0 == memcmp("vendor", cp, 6)))) {
188 fprintf(stderr, "%x,%x differ, ref: %s, sg_lib_data: "
189 "<missing>\n", asc, ascq, b);
190 continue;
191 }
192 if (num > 20) {
193 cp += 18;
194 num -= 18;
195 for (j = 0; j < num; ++j)
196 cp[j] = toupper(cp[j]);
197 }
198 if (0 != strcmp(b, cp))
199 fprintf(stderr, "%x,%x differ, ref: %s, sg_lib_data: "
200 "%s\n", asc, ascq, b, cp);
201 }
202 }
203 if (NULL == cp) {
204 if (feof(fp)) {
205 if (verbose > 2)
206 fprintf(stderr, "EOF detected\n");
207 } else
208 fprintf(stderr, "fgets: %s\n", safe_strerror(errno));
209 } else
210 fprintf(stderr, "%s\n", line);
211
212 res = fclose(fp);
213 if (EOF == res) {
214 fprintf(stderr, "close error: %s\n", safe_strerror(errno));
215 return 1;
216 }
217 return ret;
218 }
219