/* * smart monitoring for scsi and ata * copyright © 2009 erik quanstrom */#include <u.h>#include <libc.h>#include <fis.h>#include "smart.h" enum{ Checksec = 600, Opensec = 60 * 60, Relogsec = 38400 / 4,}; static Sdisk *disks;static Dtype dtab[] = { Tata, "ata", ataprobe, ataenable, atastatus, Tscsi, "scsi", scsiprobe, scsienable, scsistatus,};static char *logfile = "smart";static int aflag;static int tflag;static int vflag; voideprint(Sdisk *d, char *s, ...){ char buf[256]; va_list arg; va_start(arg, s); vseprint(buf, buf + sizeof buf, s, arg); va_end(arg);// syslog(0, logfile, "%s: %s", d->name, buf); if(vflag) fprint(2, "%s: %s", d->name, buf);} voidsmartlog(Sdisk *d, char *s, ...){ char buf[256]; va_list arg; va_start(arg, s); vseprint(buf, buf + sizeof buf, s, arg); va_end(arg); if(!tflag) syslog(0, logfile, "%s: %s", d->name, buf); if(tflag || vflag) fprint(2, "%s: %s\n", d->name, buf);} static voiddiskclose(Sdisk *d){ close(d->fd); d->fd = -1;} static intdiskopen(Sdisk *d){ char buf[128]; snprint(buf, sizeof buf, "%s/raw", d->path); werrstr(""); return d->fd = open(buf, ORDWR);} static intnoexist(void){ char buf[ERRMAX]; errstr(buf, sizeof buf); if(strstr(buf, "exist")) return -1; return 0;} static voidlognew(Sdisk *d){ if(aflag && !tflag) smartlog(d, d->t->tname);} static intnewdisk(char *s){ char buf[128], *p; int i; Sdisk d; memset(&d, 0, sizeof d); snprint(d.path, sizeof d.path, "%s", s); if(p = strrchr(s, '/')) p++; else p = s; snprint(d.name, sizeof d.name, "%s", p); snprint(buf, sizeof buf, "%s/raw", s); if(diskopen(&d) == -1) return noexist(); for(i = 0; i < nelem(dtab); i++) if(dtab[i].probe(&d) == 0) if(dtab[i].enable(&d) == 0){ d.t = dtab + i; lognew(&d); break; } diskclose(&d); if(d.t != 0){ d.next = disks; disks = malloc(sizeof d); memmove(disks, &d, sizeof d); } return 0;} static intprobe0(char *s, int l){ char *p, *f[3], buf[16]; int i; s[l] = 0; for(; p = strchr(s, '\n'); s = p + 1){ if(tokenize(s, f, nelem(f)) < 1) continue; for(i = 0; i < 0x10; i++){ snprint(buf, sizeof buf, "/dev/%s%ux", f[0], i); if(newdisk(buf) == -1 && i > 2) break; } } return -1;} intprobe(void){ char *s; int fd, l, r; fd = open("/dev/sdctl", OREAD); if(fd == -1) return -1; r = -1; l = 1024; /* #S/sdctl has 0 size; guess */ if(s = malloc(l + 1)) if((l = read(fd, s, l)) > 0) r = probe0(s, l); free(s); close(fd); return r;} voidrun(void){ char buf[1024]; int e, s0; uvlong t, t0; Sdisk *d; e = 0; t = time(0); for(d = disks; d; d = d->next){ t0 = d->lastcheck; if(t0 != 0 && t - t0 < Checksec) continue; if(diskopen(d) == -1){ if(t - t0 > Opensec) smartlog(d, "can't open in %ullds\n", t - t0); continue; } s0 = d->status; d->status = d->t->status(d, buf, sizeof buf); diskclose(d); if(d->status == -1) e++; if((aflag || d->status != s0 || d->status != 0) && !d->silent){ t0 = d->lastlog; if(t0 == 0 || t - t0 >= Relogsec){ smartlog(d, buf); d->lastlog = t; } }else d->lastlog = 0; d->lastcheck = t; } if(tflag) exits(e? "smart errors": "");} voidusage(void){ fprint(2, "usage: disk/smart [-aptv] [/dev/sdXX] ...\n"); exits("usage");} voidmain(int argc, char **argv){ int pflag; pflag = 0; ARGBEGIN{ case 'a': aflag = 1; break; case 'p': pflag = 1; break; case 't': tflag = 1; case 'v': vflag = 1; break; default: usage(); }ARGEND for(; *argv; argv++) newdisk(*argv); if(argc == 0 || pflag) probe(); if(disks == nil) sysfatal("no disks"); for(;; sleep(30*1000)) run();}
/*
* smart monitoring for scsi and ata
* copyright © 2009 erik quanstrom
*/
#include <u.h>
#include <libc.h>
#include <fis.h>
#include "smart.h"
enum{
Checksec = 600,
Opensec = 60 * 60,
Relogsec = 38400 / 4,
};
static Sdisk *disks;
static Dtype dtab[] = {
Tata, "ata", ataprobe, ataenable, atastatus,
Tscsi, "scsi", scsiprobe, scsienable, scsistatus,
};
static char *logfile = "smart";
static int aflag;
static int tflag;
static int vflag;
void
eprint(Sdisk *d, char *s, ...)
{
char buf[256];
va_list arg;
va_start(arg, s);
vseprint(buf, buf + sizeof buf, s, arg);
va_end(arg);
// syslog(0, logfile, "%s: %s", d->name, buf);
if(vflag)
fprint(2, "%s: %s", d->name, buf);
}
void
smartlog(Sdisk *d, char *s, ...)
{
char buf[256];
va_list arg;
va_start(arg, s);
vseprint(buf, buf + sizeof buf, s, arg);
va_end(arg);
if(!tflag)
syslog(0, logfile, "%s: %s", d->name, buf);
if(tflag || vflag)
fprint(2, "%s: %s\n", d->name, buf);
}
static void
diskclose(Sdisk *d)
{
close(d->fd);
d->fd = -1;
}
static int
diskopen(Sdisk *d)
{
char buf[128];
snprint(buf, sizeof buf, "%s/raw", d->path);
werrstr("");
return d->fd = open(buf, ORDWR);
}
static int
noexist(void)
{
char buf[ERRMAX];
errstr(buf, sizeof buf);
if(strstr(buf, "exist"))
return -1;
return 0;
}
static void
lognew(Sdisk *d)
{
if(aflag && !tflag)
smartlog(d, d->t->tname);
}
static int
newdisk(char *s)
{
char buf[128], *p;
int i;
Sdisk d;
memset(&d, 0, sizeof d);
snprint(d.path, sizeof d.path, "%s", s);
if(p = strrchr(s, '/'))
p++;
else
p = s;
snprint(d.name, sizeof d.name, "%s", p);
snprint(buf, sizeof buf, "%s/raw", s);
if(diskopen(&d) == -1)
return noexist();
for(i = 0; i < nelem(dtab); i++)
if(dtab[i].probe(&d) == 0)
if(dtab[i].enable(&d) == 0){
d.t = dtab + i;
lognew(&d);
break;
}
diskclose(&d);
if(d.t != 0){
d.next = disks;
disks = malloc(sizeof d);
memmove(disks, &d, sizeof d);
}
return 0;
}
static int
probe0(char *s, int l)
{
char *p, *f[3], buf[16];
int i;
s[l] = 0;
for(; p = strchr(s, '\n'); s = p + 1){
if(tokenize(s, f, nelem(f)) < 1)
continue;
for(i = 0; i < 0x10; i++){
snprint(buf, sizeof buf, "/dev/%s%ux", f[0], i);
if(newdisk(buf) == -1 && i > 2)
break;
}
}
return -1;
}
int
probe(void)
{
char *s;
int fd, l, r;
fd = open("/dev/sdctl", OREAD);
if(fd == -1)
return -1;
r = -1;
l = 1024; /* #S/sdctl has 0 size; guess */
if(s = malloc(l + 1))
if((l = read(fd, s, l)) > 0)
r = probe0(s, l);
free(s);
close(fd);
return r;
}
void
run(void)
{
char buf[1024];
int e, s0;
uvlong t, t0;
Sdisk *d;
e = 0;
t = time(0);
for(d = disks; d; d = d->next){
t0 = d->lastcheck;
if(t0 != 0 && t - t0 < Checksec)
continue;
if(diskopen(d) == -1){
if(t - t0 > Opensec)
smartlog(d, "can't open in %ullds\n", t - t0);
continue;
}
s0 = d->status;
d->status = d->t->status(d, buf, sizeof buf);
diskclose(d);
if(d->status == -1)
e++;
if((aflag || d->status != s0 || d->status != 0) && !d->silent){
t0 = d->lastlog;
if(t0 == 0 || t - t0 >= Relogsec){
smartlog(d, buf);
d->lastlog = t;
}
}else
d->lastlog = 0;
d->lastcheck = t;
}
if(tflag)
exits(e? "smart errors": "");
}
void
usage(void)
{
fprint(2, "usage: disk/smart [-aptv] [/dev/sdXX] ...\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int pflag;
pflag = 0;
ARGBEGIN{
case 'a':
aflag = 1;
break;
case 'p':
pflag = 1;
break;
case 't':
tflag = 1;
case 'v':
vflag = 1;
break;
default:
usage();
}ARGEND
for(; *argv; argv++)
newdisk(*argv);
if(argc == 0 || pflag)
probe();
if(disks == nil)
sysfatal("no disks");
for(;; sleep(30*1000))
run();
}