smartmontools SVN Rev 5599
Utility to control and monitor storage systems with "S.M.A.R.T."
os_solaris.cpp
Go to the documentation of this file.
1/*
2 * os_solaris.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2003-08 SAWADA Keiji
7 * Copyright (C) 2003-15 Casper Dik
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include <stdlib.h>
13#include <ctype.h>
14#include <string.h>
15#include <dirent.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <fcntl.h>
19#include <sys/param.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22
23// These are needed to define prototypes for the functions defined below
24#include "config.h"
25
26#include "atacmds.h"
27#include "scsicmds.h"
28#include "utility.h"
29
30const char * os_solaris_cpp_cvsid = "$Id: os_solaris.cpp 5393 2022-05-29 05:08:10Z dpgilbert $";
31
32// print examples for smartctl
34 printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
35 " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n"
36 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n"
37 " (Enables SMART on first disk)\n\n"
38 " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n"
39 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n"
40 " (Prints Self-Test & Attribute errors)\n"
41 );
42 return;
43}
44
45static const char *uscsidrvrs[] = {
46 "sd",
47 "ssd",
48 "disk", // SATA devices
49 "st"
50};
51
52static const char *atadrvrs[] = {
53 "cmdk",
54 "dad",
55};
56
57static int
58isdevtype(const char *dev_name, const char *table[], int tsize)
59{
60 char devpath[MAXPATHLEN];
61 int i;
62 char *basename;
63
64 if (realpath(dev_name, devpath) == NULL)
65 return 0;
66
67 if ((basename = strrchr(devpath, '/')) == NULL)
68 return 0;
69
70 basename++;
71
72 for (i = 0; i < tsize; i++) {
73 int l = strlen(table[i]);
74 if (strncmp(basename, table[i], l) == 0 && basename[l] == '@')
75 return 1;
76 }
77 return 0;
78}
79
80static int
81isscsidev(const char *path)
82{
83 return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *));
84}
85
86static int
87isatadev(const char *path)
88{
89 return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *));
90}
91
92// tries to guess device type given the name (a path)
93int guess_device_type (const char* dev_name) {
94 if (isscsidev(dev_name))
95 return CONTROLLER_SCSI;
96 else if (isatadev(dev_name))
97 return CONTROLLER_ATA;
98 else
99 return CONTROLLER_UNKNOWN;
100}
101
102struct pathlist {
103 char **names;
106};
107
108static int
109addpath(const char *path, struct pathlist *res)
110{
111 if (++res->nnames > res->maxnames) {
112 res->maxnames += 16;
113 res->names = static_cast<char**>(realloc(res->names, res->maxnames * sizeof (char *)));
114 if (res->names == NULL)
115 return -1;
116 }
117 if (!(res->names[res->nnames-1] = strdup(path)))
118 return -1;
119 return 0;
120}
121
122static int
123grokdir(const char *dir, struct pathlist *res, int testfun(const char *))
124{
125 char pathbuf[MAXPATHLEN];
126 size_t len;
127 DIR *dp;
128 struct dirent *de;
129 int isdisk = strstr(dir, "dsk") != NULL;
130 char *p;
131
132 len = snprintf(pathbuf, sizeof (pathbuf), "%s/", dir);
133 if (len >= sizeof (pathbuf))
134 return -1;
135
136 dp = opendir(dir);
137 if (dp == NULL)
138 return 0;
139
140 while ((de = readdir(dp)) != NULL) {
141 if (de->d_name[0] == '.')
142 continue;
143
144 if (strlen(de->d_name) + len >= sizeof (pathbuf))
145 continue;
146
147 if (isdisk) {
148 /* Disk represented by slice 0 */
149 p = strstr(de->d_name, "s0");
150 /* String doesn't end in "s0\0" */
151 if (p == NULL || p[2] != '\0')
152 continue;
153 } else {
154 /* Tape drive represented by the all-digit device */
155 for (p = de->d_name; *p; p++)
156 if (!isdigit((int)(*p)))
157 break;
158 if (*p != '\0')
159 continue;
160 }
161 strcpy(&pathbuf[len], de->d_name);
162 if (testfun(pathbuf)) {
163 if (addpath(pathbuf, res) == -1) {
164 closedir(dp);
165 return -1;
166 }
167 }
168 }
169 closedir(dp);
170
171 return 0;
172}
173
174// makes a list of ATA or SCSI devices for the DEVICESCAN directive of
175// smartd. Returns number of devices, or -1 if out of memory.
176int make_device_names (char*** devlist, const char* name) {
177 struct pathlist res;
178
179 res.nnames = res.maxnames = 0;
180 res.names = NULL;
181 if (strcmp(name, "SCSI") == 0) {
182 if (grokdir("/dev/rdsk", &res, isscsidev) == -1)
183 return -1;
184 if (grokdir("/dev/rmt", &res, isscsidev) == -1)
185 return -1;
186 } else if (strcmp(name, "ATA") == 0) {
187 if (grokdir("/dev/rdsk", &res, isatadev) == -1)
188 return -1;
189 } else {
190 // non-SCSI and non-ATA case not implemented
191 *devlist=NULL;
192 return 0;
193 }
194
195 // shrink array to min possible size
196 res.names = static_cast<char**>(realloc(res.names, res.nnames * sizeof (char *)));
197
198 // pass list back
199 *devlist = res.names;
200 return res.nnames;
201}
202
203// Like open(). Return integer handle, used by functions below only.
204// type="ATA" or "SCSI".
205int deviceopen(const char *pathname, char *type){
206 if (!strcmp(type,"SCSI"))
207 return open(pathname, O_RDWR | O_NONBLOCK);
208 else if (!strcmp(type,"ATA"))
209 return open(pathname, O_RDONLY | O_NONBLOCK);
210 else
211 return -1;
212}
213
214// Like close(). Acts on handles returned by above function.
215int deviceclose(int fd){
216 return close(fd);
217}
218
219// Interface to ATA devices.
221{
222 pout("Device type 'ata' not implemented, try '-d sat' or '-d sat,12' instead.\n");
223 errno = ENOSYS;
224 return -1;
225}
226
227#include <errno.h>
228#include <sys/scsi/generic/commands.h>
229#include <sys/scsi/generic/status.h>
230#include <sys/scsi/impl/types.h>
231#include <sys/scsi/impl/uscsi.h>
232
233// Interface to SCSI devices.
234int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
235{
236 struct uscsi_cmd uscsi;
237
238 if (report > 0) {
239 int k;
240 const unsigned char * ucp = iop->cmnd;
241 const char * np;
242
243 np = scsi_get_opcode_name(ucp);
244 pout(" [%s: ", np ? np : "<unknown opcode>");
245 for (k = 0; k < (int)iop->cmnd_len; ++k)
246 pout("%02x ", ucp[k]);
247 pout("]\n");
248 if ((report > 1) &&
249 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
250 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
251
252 pout(" Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
253 (trunc ? " [only first 256 bytes shown]" : ""));
254 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
255 }
256 }
257 memset(&uscsi, 0, sizeof (uscsi));
258
259 uscsi.uscsi_cdb = reinterpret_cast<char*>(iop->cmnd);
260 uscsi.uscsi_cdblen = iop->cmnd_len;
261 if (iop->timeout == 0)
262 uscsi.uscsi_timeout = 60; /* 60 seconds */
263 else
264 uscsi.uscsi_timeout = iop->timeout;
265 uscsi.uscsi_bufaddr = reinterpret_cast<char*>(iop->dxferp);
266 uscsi.uscsi_buflen = iop->dxfer_len;
267 uscsi.uscsi_rqbuf = reinterpret_cast<char*>(iop->sensep);
268 uscsi.uscsi_rqlen = iop->max_sense_len;
269
270 switch (iop->dxfer_dir) {
271 case DXFER_NONE:
273 uscsi.uscsi_flags = USCSI_READ;
274 break;
275 case DXFER_TO_DEVICE:
276 uscsi.uscsi_flags = USCSI_WRITE;
277 break;
278 default:
279 return -EINVAL;
280 }
281 uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE | USCSI_SILENT);
282
283 if (ioctl(fd, USCSICMD, &uscsi)) {
284 int err = errno;
285
286 if (! ((EIO == err) && uscsi.uscsi_status))
287 return -err;
288 /* errno is set to EIO when a non-zero SCSI completion status given */
289 }
290
291 iop->scsi_status = uscsi.uscsi_status;
292 iop->resid = uscsi.uscsi_resid;
293 iop->resp_sense_len = iop->max_sense_len - uscsi.uscsi_rqresid;
294
295 if (report > 0) {
296 int trunc;
297 int len = iop->resp_sense_len;
298
300 iop->sensep && (len > 3)) {
301 if ((iop->sensep[0] & 0x7f) > 0x71)
302 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
303 iop->scsi_status, iop->sensep[1] & 0xf,
304 iop->sensep[2], iop->sensep[3]);
305 else
306 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
307 iop->scsi_status, iop->sensep[2] & 0xf,
308 iop->sensep[12], iop->sensep[13]);
309 if (report > 1) {
310 pout(" >>> Sense buffer, len=%d:\n", len);
311 dStrHex(iop->sensep, ((len > 252) ? 252 : len) , 1);
312 }
313 } else if (iop->scsi_status)
314 pout(" status=%x\n", iop->scsi_status);
315 if (iop->resid)
316 pout(" dxfer_len=%d, resid=%d\n", iop->dxfer_len, iop->resid);
317 if (report > 1) {
318 len = iop->dxfer_len - iop->resid;
319 if (len > 0) {
320 trunc = (len > 256) ? 1 : 0;
321 pout(" Incoming data, len=%d%s:\n", len,
322 (trunc ? " [only first 256 bytes shown]" : ""));
323 dStrHex(iop->dxferp, (trunc ? 256 : len) , 1);
324 }
325 }
326 }
327 return 0;
328}
smart_command_set
Definition: atacmds.h:29
static int addpath(const char *path, struct pathlist *res)
Definition: os_solaris.cpp:109
static int isatadev(const char *path)
Definition: os_solaris.cpp:87
int deviceclose(int fd)
Definition: os_solaris.cpp:215
int make_device_names(char ***devlist, const char *name)
Definition: os_solaris.cpp:176
static const char * uscsidrvrs[]
Definition: os_solaris.cpp:45
static int isdevtype(const char *dev_name, const char *table[], int tsize)
Definition: os_solaris.cpp:58
const char * os_solaris_cpp_cvsid
Definition: os_solaris.cpp:30
int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io *iop, int report)
Definition: os_solaris.cpp:234
int deviceopen(const char *pathname, char *type)
Definition: os_solaris.cpp:205
static int grokdir(const char *dir, struct pathlist *res, int testfun(const char *))
Definition: os_solaris.cpp:123
static const char * atadrvrs[]
Definition: os_solaris.cpp:52
int guess_device_type(const char *dev_name)
Definition: os_solaris.cpp:93
void print_smartctl_examples()
Definition: os_solaris.cpp:33
int ata_command_interface(int, smart_command_set, int, char *)
Definition: os_solaris.cpp:220
static int isscsidev(const char *path)
Definition: os_solaris.cpp:81
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:368
const char * scsi_get_opcode_name(const uint8_t *cdbp)
Definition: scsicmds.cpp:511
#define DXFER_NONE
Definition: scsicmds.h:108
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:109
#define DXFER_TO_DEVICE
Definition: scsicmds.h:110
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:320
void pout(const char *fmt,...)
Definition: smartd.cpp:1338
int maxnames
Definition: os_solaris.cpp:105
char ** names
Definition: os_solaris.cpp:103
uint8_t * sensep
Definition: scsicmds.h:123
uint8_t * dxferp
Definition: scsicmds.h:121
int dxfer_dir
Definition: scsicmds.h:119
size_t cmnd_len
Definition: scsicmds.h:118
size_t resp_sense_len
Definition: scsicmds.h:127
size_t dxfer_len
Definition: scsicmds.h:122
size_t max_sense_len
Definition: scsicmds.h:125
uint8_t scsi_status
Definition: scsicmds.h:128
uint8_t * cmnd
Definition: scsicmds.h:117
unsigned timeout
Definition: scsicmds.h:126