summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2001-08-28 23:00:28 +0000
committerobrien <obrien@FreeBSD.org>2001-08-28 23:00:28 +0000
commitd350edf744aae32de95d06c856373a03f2f92bc3 (patch)
tree103f791e64fb81349e7ee4e6b59e795979e73266
parentf3aeba4a67b48dad63fa772a8288bcc60631a1b7 (diff)
downloadFreeBSD-src-d350edf744aae32de95d06c856373a03f2f92bc3.zip
FreeBSD-src-d350edf744aae32de95d06c856373a03f2f92bc3.tar.gz
Remove `diskcheckd'. It is now in ports/sysutils.
Consensus on: freebsd-current.
-rw-r--r--etc/diskcheckd.conf30
-rw-r--r--usr.sbin/diskcheckd/Makefile9
-rw-r--r--usr.sbin/diskcheckd/diskcheckd.8190
-rw-r--r--usr.sbin/diskcheckd/diskcheckd.c863
4 files changed, 0 insertions, 1092 deletions
diff --git a/etc/diskcheckd.conf b/etc/diskcheckd.conf
deleted file mode 100644
index 86e3c30..0000000
--- a/etc/diskcheckd.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-# $FreeBSD$
-#
-# Configuration file for diskcheckd, refer to the diskcheckd.conf(5) manual
-# page for further information.
-#
-# First, a line starting with an exclamation mark should contain only one
-# extra field which specifies disk types which should not be included in
-# wildcard expansions. By default CD-ROM drives and memory disks are
-# excluded.
-#
-!acd
-!cd
-!matcd
-!mcd
-!scd
-!md
-#
-# The device name may be specified as "*", in which case all devices are
-# checked.
-#
-# The size may be specified as "*", in which case the size is automatically
-# determined from the disklabel.
-#
-# One of either "Days" or "Rate" must be specified, to specify a complete
-# scan should happen once every n days, or that scanning should take place
-# at n KB/s. Note that the "Days" value will not cause a scan exactly every
-# n days since diskcheckd will always read in power-of-2 size blocks.
-#
-# Device Size Days Rate
-* * 28 *
diff --git a/usr.sbin/diskcheckd/Makefile b/usr.sbin/diskcheckd/Makefile
deleted file mode 100644
index 265acaa..0000000
--- a/usr.sbin/diskcheckd/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-BINDIR?= /usr/sbin
-
-PROG= diskcheckd
-MAN8= diskcheckd.8
-MLINKS= diskcheckd.8 diskcheckd.conf.5
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/diskcheckd/diskcheckd.8 b/usr.sbin/diskcheckd/diskcheckd.8
deleted file mode 100644
index 83d7878..0000000
--- a/usr.sbin/diskcheckd/diskcheckd.8
+++ /dev/null
@@ -1,190 +0,0 @@
-.\" Copyright (c) 2000, 2001 Ben Smithurst <ben@FreeBSD.org>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd July 4, 2001
-.Dt DISKCHECKD 8
-.Os
-.Sh NAME
-.Nm diskcheckd
-.Nd daemon to check for disk read errors
-.Sh SYNOPSIS
-.Nm
-.Op Fl d
-.Op Fl f Ar conf_file
-.Op Fl o Ar save_file
-.Sh DESCRIPTION
-.Nm
-is a daemon which runs in the background,
-reading entire disks to find any read errors on those disks.
-The disks which should be scanned,
-and the rates at which they should be scanned,
-must be specified in the configuration file,
-which is
-.Pa /etc/diskcheckd.conf
-by default.
-.Pp
-Any blank lines or lines starting with a
-.Ql #
-character in this file are ignored.
-Each non-comment line of this file must be in one of two formats.
-The first format is
-.Ql !xx ,
-and specifies that device names matching
-.Pa /dev/xx*
-should not be included in expansion of wildcards (see below).
-The second format consists of four white space separated
-fields,
-which are the full pathname of the disk device,
-the size of that disk,
-the frequency in days at which to check that disk,
-and the rate in kilobytes per second at which to check this disk.
-Naturally,
-it would be contradictory to specify both the frequency and the rate,
-so only one of these should be specified.
-Additionally,
-the size of the disk should not be specified if the rate is specified,
-as this information is unnecessary.
-.Pp
-If the disk is specified as
-.Dq * ,
-then
-.Nm
-will apply the given settings to all disks in the system,
-obtained using the
-.Va kern.disks
-sysctl variable.
-If the size is specified as
-.Dq *
-(recommended),
-then the size of the disk will be automatically determined from the
-disklabel,
-if possible.
-Fields which are not specified should contain a single
-.Dq *
-character.
-.Pp
-Note that
-.Nm
-always reads data from the disk in 64KB blocks,
-so the rate your specify may not be the exact rate at which the disk is
-actually checked.
-Similarly,
-if you specify the third field (days for complete scan) it is unlikely
-that a complete scan will actually take exactly this many days.
-.Pp
-To run
-.Nm
-automatically at boot time,
-the
-.Va diskcheckd_enable
-variable in
-.Xr rc.conf 5
-should be set to
-.Dq YES .
-.Pp
-When
-.Nm
-receives a
-.Dv SIGTERM
-or
-.Dv SIGINT
-signal,
-it saves its current state information to a file,
-so that after a reboot
-.Nm
-can resume reading from where it left off,
-rather than starting from the beginning of the disk again.
-The information saved to this file consists of the device filename and the
-current offset into that device.
-.Pp
-.Nm
-can be instructed to reload the configuration file by sending it a
-.Dv SIGHUP
-signal.
-.Pp
-.Nm
-accepts the following command line options:
-.Bl -tag -width Fl
-.It Fl d
-If this flag is specified,
-.Nm
-will not fork into the background and detach from its controlling terminal
-to become a daemon.
-This flag is primarily used for debugging.
-.It Fl f
-Specify the configuration file to use,
-instead of the default
-.Pa /etc/diskcheckd.conf .
-.It Fl o
-Specify the file to save disk offsets to,
-instead of the default
-.Pa /var/db/diskcheckd.offsets .
-.El
-.Sh FILES
-.Bl -tag -width /var/db/diskcheckd.offsets -compact
-.It Pa /etc/diskcheckd.conf
-Default configuration file.
-.It Pa /var/db/diskcheckd.offsets
-Default location of saved offsets.
-.El
-.Sh EXAMPLES
-To check all of
-.Pa /dev/ad0
-for errors once every two weeks,
-use this entry in
-.Pa diskcheckd.conf :
-.Bd -literal -offset indent
-/dev/ad0 * 14 *
-.Ed
-.Pp
-To check the first SCSI disk for errors at approximately 64KB/s,
-use the following entry:
-.Bd -literal -offset indent
-/dev/da0 * * 64
-.Ed
-.Pp
-To check all disks once every four weeks:
-.Bd -literal -offset indent
-* * 28 *
-.Ed
-.Sh DIAGNOSTICS
-If any errors occur,
-they will be written to
-.Xr syslogd 8 .
-.Sh HISTORY
-.Nm
-first appeared in
-.Fx 5.0 .
-.Sh AUTHORS
-.An -nosplit
-.Nm
-and this manual page were written by
-.An Ben Smithurst Aq ben@FreeBSD.org ,
-with input from
-.An Poul-Henning Kamp Aq phk@FreeBSD.org .
-.Sh BUGS
-.Nm
-assumes all disks have 512 byte sectors.
diff --git a/usr.sbin/diskcheckd/diskcheckd.c b/usr.sbin/diskcheckd/diskcheckd.c
deleted file mode 100644
index 0b41bec..0000000
--- a/usr.sbin/diskcheckd/diskcheckd.c
+++ /dev/null
@@ -1,863 +0,0 @@
-/*-
- * Copyright (c) 2000, 2001 Ben Smithurst <ben@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-static const char rcsid[] =
- "$FreeBSD$";
-
-#include <sys/types.h>
-#include <sys/sysctl.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#define DKTYPENAMES
-#include <sys/disklabel.h>
-
-#define _PATH_CONF "/etc/diskcheckd.conf"
-#define _PATH_SAVE _PATH_VARDB"diskcheckd.offsets"
-
-#define READ_SIZE (64 << 10)
-
-struct disk {
- int fd;
- char *device;
- off_t size;
- int secsize;
- int days, rate, errors, interval, next;
-};
-
-volatile sig_atomic_t got_sighup = 0, got_sigterm = 0;
-
-char **getdisknames(char **, int);
-off_t dseek(struct disk *, off_t, int);
-struct disk *readconf(const char *);
-void getdisksize(struct disk *);
-void logreaderror(struct disk *, int);
-void readchunk(struct disk *, char *);
-void readoffsets(struct disk *, const char *);
-void sighup(int);
-void sigterm(int);
-void updateproctitle(struct disk *);
-void usage(void);
-void writeoffsets(struct disk *, const char *);
-
-int
-main(int argc, char *argv[]) {
- char *buf;
- struct disk *disks, *dp;
- int ch, ok, minwait, nextwait;
- struct sigaction sa;
- int counter, debug;
- const char *conf_file, *save_file;
-
- conf_file = _PATH_CONF;
- save_file = _PATH_SAVE;
- debug = 0;
-
- while ((ch = getopt(argc, argv, "df:o:")) != -1)
- switch (ch) {
- case 'd':
- debug = 1;
- break;
- case 'f':
- conf_file = optarg;
- break;
- case 'o':
- save_file = optarg;
- break;
- default:
- usage();
- /* NOTREACHED */
- }
-
- argv += optind;
- argc -= optind;
-
- if (argc != 0)
- usage();
-
- openlog("diskcheckd", LOG_CONS|LOG_PID, LOG_DAEMON);
-
- if (!debug && daemon(0, 0) < 0) {
- syslog(LOG_NOTICE, "daemon failure: %m");
- exit(EXIT_FAILURE);
- }
-
- sa.sa_handler = sigterm;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
-
- sa.sa_handler = sighup;
- sigaction(SIGHUP, &sa, NULL);
-
- /* Read the configuration file and the saved offsets */
- disks = readconf(conf_file);
- readoffsets(disks, save_file);
-
- if ((buf = malloc(READ_SIZE)) == NULL) {
- syslog(LOG_NOTICE, "malloc failure: %m");
- exit(EXIT_FAILURE);
- }
-
- /* The main disk checking loop.
- *
- * We wait the shortest amount of time we need to before
- * another disk is due for a read -- this time is updated
- * in the 'nextwait' variable, which is then copied to
- * 'minwait'. After a sleep, 'minwait' is subtracted from
- * each disk's 'next' field, and when that reaches zero,
- * that disk is read again.
- */
- counter = 0;
- minwait = 0;
- while (!got_sigterm) {
- ok = 0;
- nextwait = INT_MAX;
- for (dp = disks; dp->device != NULL; dp++)
- if (dp->fd != -1) {
- if ((dp->next -= minwait) == 0) {
- ok = 1;
- readchunk(dp, buf);
- }
-
- /* XXX debugging */
- if (dp->next < 0) {
- syslog(LOG_NOTICE,
- "dp->next < 0 for %s", dp->device);
- abort();
- }
-
- if (dp->next < nextwait)
- nextwait = dp->next;
- }
-
- if (!ok) {
- syslog(LOG_EMERG, "all disks had read errors");
- exit(EXIT_FAILURE);
- }
-
- if (counter >= 300) {
- updateproctitle(disks);
- writeoffsets(disks, save_file);
- counter = 0;
- }
-
- minwait = nextwait;
- sleep(minwait);
- counter += minwait;
-
- if (got_sighup) {
- /*
- * Got a SIGHUP, so save the offsets, free the
- * memory used for the disk structures, and then
- * re-read the config file and the disk offsets.
- */
- writeoffsets(disks, save_file);
- for (dp = disks; dp->device != NULL; dp++) {
- free(dp->device);
- close(dp->fd);
- }
- free(disks);
- disks = readconf(conf_file);
- readoffsets(disks, save_file);
- got_sighup = 0;
- }
- }
-
- writeoffsets(disks, save_file);
- return (EXIT_SUCCESS);
-}
-
-/*
- * Read the next chunk from the specified disk, retrying if necessary.
- */
-void
-readchunk(struct disk *dp, char *buf) {
- ssize_t n;
- int s;
-
- dp->next = dp->interval;
- n = read(dp->fd, buf, READ_SIZE);
- if (n == 0) {
- eof:
- syslog(LOG_INFO, "reached end of %s with %d errors",
- dp->device, dp->errors);
- dseek(dp, 0, SEEK_SET);
- dp->errors = 0;
- return;
- } else if (n > 0)
- return;
-
- /*
- * Read error, retry in smaller chunks.
- */
- logreaderror(dp, READ_SIZE);
-
- for (s = 0; s < READ_SIZE; s += 512) {
- n = read(dp->fd, buf, 512);
- if (n == 0)
- goto eof;
- else if (n < 0) {
- /* log the error and seek past it. */
- logreaderror(dp, 512);
- dseek(dp, 512, SEEK_CUR);
- }
- }
-}
-
-const char *
-fstypename(u_int8_t type) {
- static char buf[32];
-
- if (type < FSMAXTYPES)
- return (fstypenames[type]);
- else {
- snprintf(buf, sizeof buf, "%u", type);
- return (buf);
- }
-}
-
-/*
- * Report a read error, logging how many bytes were trying to be read, which
- * sector they were being read from, and try to also find out what that sector
- * is used for.
- */
-void
-logreaderror(struct disk *dp, int nbytes) {
- quad_t secno;
- off_t saved_offset;
- int fd, slice, part;
- struct dos_partition *dos;
- struct disklabel label;
- char buf[512];
- char newdev[512];
-
- saved_offset = dseek(dp, 0, SEEK_CUR);
- secno = (quad_t)saved_offset / dp->secsize;
- dp->errors++;
-
- syslog(LOG_NOTICE, "error reading %d bytes from sector %qd on %s",
- nbytes, secno, dp->device);
-
- /*
- * First, find out which slice it's in. To do this, we seek to the
- * start of the disk, read the first sector, and go through the DOS
- * slice table.
- */
- if (dseek(dp, 0, SEEK_SET) == -1)
- exit(EXIT_FAILURE);
-
- if (read(dp->fd, buf, sizeof buf) != sizeof buf) {
- dseek(dp, saved_offset, SEEK_SET);
- return;
- }
-
- /* seek back to where we were */
- if (dseek(dp, saved_offset, SEEK_SET) == -1)
- exit(EXIT_FAILURE);
-
- dos = (struct dos_partition *)&buf[DOSPARTOFF];
- for (slice = 0; slice < NDOSPART; slice++)
- if (dos[slice].dp_start <= secno &&
- secno < dos[slice].dp_start + dos[slice].dp_size)
- break;
-
- if (slice == NDOSPART) {
- syslog(LOG_NOTICE,
- "sector %qd on %s doesn't appear "
- "to be within any DOS slice", secno, dp->device);
- return;
- }
-
- /* Make secno relative to this slice */
- secno -= dos[slice].dp_start;
-
- snprintf(newdev, sizeof newdev, "%ss%d", dp->device, slice + 1);
- syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev);
-
- /* Check the type of that partition. */
- if (dos[slice].dp_typ != DOSPTYP_386BSD) {
- /* If not a BSD slice, we can't do much more. */
- syslog(LOG_NOTICE, "last bad sector is sector %qd "
- "on device %s, type %02x", secno, newdev,
- dos[slice].dp_typ);
- return;
- }
-
- if ((fd = open(newdev, O_RDONLY)) < 0) {
- syslog(LOG_NOTICE, "open %s failure: %m", newdev);
- return;
- }
-
- /* Try to read the disklabel from that device. */
- if (ioctl(fd, DIOCGDINFO, &label) < 0) {
- syslog(LOG_NOTICE, "DIOCGDINFO on %s failed: %m",
- newdev);
- return;
- }
-
- /* Check which partition this sector is in. */
- for (part = 0; part < MAXPARTITIONS; part++)
- if (part != 2 && /* skip 'c' partition */
- label.d_partitions[part].p_offset <= secno &&
- secno < label.d_partitions[part].p_offset +
- label.d_partitions[part].p_size)
- break;
-
- if (part == MAXPARTITIONS) {
- syslog(LOG_NOTICE,
- "sector %qd on %s doesn't appear "
- "to be within any BSD partition", secno, newdev);
- return;
- }
-
- secno -= label.d_partitions[part].p_offset;
- snprintf(newdev, sizeof newdev, "%ss%d%c",
- dp->device, slice + 1, 'a' + part);
- syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev);
- if (label.d_partitions[part].p_fstype != FS_BSDFFS) {
- /* Again, if not a BSD partition, can't do much. */
- syslog(LOG_NOTICE, "last bad sector is sector %qd "
- "on device %s, type %s", secno, newdev,
- fstypename(label.d_partitions[part].p_fstype));
- return;
- }
-
- syslog(LOG_NOTICE, "last bad sector is sector %qd "
- "on 4.2BSD filesystem %s", secno, newdev);
-
- /*
- * XXX: todo: find out which file on the BSD filesystem uses this
- * sector...
- */
-}
-
-/*
- * Read the offsets written by writeoffsets().
- */
-void
-readoffsets(struct disk *disks, const char *save_file) {
- FILE *fp;
- struct disk *dp;
- char *space, buf[1024];
-
- if ((fp = fopen(save_file, "r")) == NULL) {
- if (errno != ENOENT)
- syslog(LOG_NOTICE, "open %s failed: %m", save_file);
- return;
- }
-
- while (fgets(buf, sizeof buf, fp) != NULL) {
- if ((space = strchr(buf, ' ')) == NULL)
- continue;
- *space = '\0';
-
- for (dp = disks;
- dp->device != NULL && strcmp(dp->device, buf) != 0; dp++)
- ; /* nothing */
-
- if (dp->device != NULL)
- dseek(dp, (off_t)strtoq(space + 1, NULL, 0), SEEK_SET);
- }
- fclose(fp);
-}
-
-/*
- * Save the offsets we've reached for each disk to a file, so we can start
- * at that position next time the daemon is started.
- */
-void
-writeoffsets(struct disk *disks, const char *save_file) {
- FILE *fp;
- struct disk *dp;
-
- if ((fp = fopen(save_file, "w")) == NULL) {
- syslog(LOG_NOTICE, "open %s failed: %m", save_file);
- return;
- }
-
- for (dp = disks; dp->device != NULL; dp++)
- if (strcmp(dp->device, "*") != 0)
- fprintf(fp, "%s %qd\n", dp->device,
- (quad_t)dseek(dp, 0, SEEK_CUR));
- fclose(fp);
-}
-
-/*
- * Set the process title so it's easy to see using ps(1) how much has been
- * done.
- */
-void
-updateproctitle(struct disk *disks) {
- struct disk *dp;
- char *bp, *p;
- static char *buf;
- static size_t bufsize;
- size_t size;
- int inc, ret;
- double percent;
-
- bp = buf;
- size = bufsize;
- for (dp = disks; dp->device != NULL; dp++) {
- p = dp->device;
- if (strcmp(p, "*") == 0)
- continue;
- if (strncmp(p, _PATH_DEV, sizeof _PATH_DEV - 1) == 0)
- p += sizeof _PATH_DEV - 1;
-
- percent = 100 * (double)dseek(dp, 0, SEEK_CUR) / dp->size;
- if ((ret = snprintf(bp, size, "%s %.2f%%, ", p, percent)) < 0)
- ret = 0;
- if ((size_t)ret >= size) {
- inc = ((ret + 1023) >> 10) << 10;
- size += inc;
- bufsize += inc;
- if ((buf = reallocf(buf, bufsize)) == NULL) {
- /* Not fatal. */
- syslog(LOG_NOTICE, "reallocf failure: %m");
- bufsize = 0;
- return;
- }
- bp = buf + bufsize - size;
- ret = snprintf(bp, size, "%s %.2f%%, ", p, percent);
- if (ret < 0)
- ret = 0;
- }
- bp += ret;
- size -= ret;
- }
-
- if (buf != NULL) {
- /* Remove the trailing comma. */
- if (&bp[-2] >= buf)
- bp[-2] = '\0';
- setproctitle("%s", buf);
- }
-}
-
-/* used to keep track of which fields have been specified */
-#define FL_SIZE_SPEC 1
-#define FL_DAYS_SPEC 2
-#define FL_RATE_SPEC 4
-
-/*
- * Read the configuration file, set the rate appropriately for each disk,
- * and get a file descriptor for each disk.
- */
-struct disk *
-readconf(const char *conf_file) {
- FILE *fp;
- char buf[1024], *line, *field, *ep, **np, **np0;
- int fields, flags;
- struct disk *disks, *dp, *odisks;
- int numdisks, onumdisks;
- double dval;
- long lval;
- int linenum;
- char **skip;
- int numskip;
-
- if ((fp = fopen(conf_file, "r")) == NULL) {
- syslog(LOG_NOTICE, "open %s failure: %m", conf_file);
- exit(EXIT_FAILURE);
- }
-
- numdisks = 0;
- disks = NULL;
- linenum = 0;
- skip = NULL;
- numskip = 0;
-
- /* Step 1: read and parse the configuration file. */
- while (fgets(buf, sizeof buf, fp) != NULL) {
- line = buf;
- linenum++;
- while (isspace(*line))
- line++;
- if (*line == '#' || *line == '\n' || *line == '\0')
- continue;
-
- /* First, if the line starts with '!', this is a disk name
- * to ignore. For example, '!md' will skip all '/dev/md*'
- * devices.
- */
- if (*line == '!') {
- line++;
- while (isspace(*line))
- line++;
- field = strsep(&line, " \t\n");
- if (field == NULL || *field == '\0') {
- syslog(LOG_NOTICE, "%s:%d: missing disk name",
- conf_file, linenum);
- continue;
- }
-
- numskip++;
- if ((skip = reallocf(skip,
- numskip * sizeof (*skip))) == NULL) {
- syslog(LOG_NOTICE, "reallocf failure: %m");
- exit(EXIT_FAILURE);
- }
-
- if ((skip[numskip-1] = strdup(field)) == NULL) {
- syslog(LOG_NOTICE, "strdup failure: %m");
- exit(EXIT_FAILURE);
- }
-
- continue;
- }
-
- fields = flags = 0;
- while ((field = strsep(&line, " \t\n")) != NULL) {
- if (*field == '\0')
- continue;
-
- /*
- * If this is the first field on a line, allocate
- * space for one more disk structure.
- */
- if (fields == 0 && (disks = reallocf(disks,
- (numdisks + 1) * sizeof (*disks))) == NULL) {
- syslog(LOG_NOTICE, "reallocf failure: %m");
- exit(EXIT_FAILURE);
- }
-
- dp = &disks[numdisks];
- switch (fields++) {
- case 0:
- /* device name */
- if ((dp->device = strdup(field)) == NULL) {
- syslog(LOG_NOTICE,
- "strdup failure: %m");
- exit(EXIT_FAILURE);
- }
- dp->fd = -1;
- dp->rate = -1;
- dp->size = -1;
- dp->interval = -1;
- dp->next = 0;
- break;
- case 1:
- /* size */
- if (strcmp(field, "*") == 0)
- break;
- flags |= FL_SIZE_SPEC;
- dval = strtod(field, &ep);
- if (dval < 0) {
- syslog(LOG_NOTICE,
- "%s:%d: size cannot be negative",
- conf_file, linenum);
- exit(EXIT_FAILURE);
- }
- if (strcasecmp(ep, "M") == 0)
- dp->size = dval * 1024 * 1024;
- else if (strcasecmp(ep, "G") == 0)
- dp->size = dval * 1024 * 1024 * 1024;
- else if (*ep == '\0')
- dp->size = dval;
- else {
- syslog(LOG_NOTICE,
- "%s:%d: bad suffix \"%s\" on "
- "size \"%s\"", conf_file,
- linenum, ep, field);
- exit(EXIT_FAILURE);
- }
- break;
- case 2:
- /* days */
- if (strcmp(field, "*") == 0)
- break;
- flags |= FL_DAYS_SPEC;
- lval = strtol(field, &ep, 0);
- if (ep == field || *ep != '\0' ||
- lval <= 0) {
- syslog(LOG_NOTICE,
- "%s:%d: bad number of days",
- conf_file, linenum);
- exit(EXIT_FAILURE);
- }
- dp->days = lval;
- break;
- case 3:
- /* rate */
- if (strcmp(field, "*") == 0)
- break;
- flags |= FL_RATE_SPEC;
- lval = strtol(field, &ep, 0);
- if (ep == field || *ep != '\0' ||
- lval <= 0) {
- syslog(LOG_NOTICE, "%s:%d: bad rate",
- conf_file, linenum);
- exit(EXIT_FAILURE);
- }
- dp->rate = lval * 1024;
- break;
- default:
- /* Report error at end of line. */
- break;
- }
- }
- if (fields != 4) {
- syslog(LOG_NOTICE,
- "%s:%d: %d fields, should be 4",
- conf_file, linenum, fields);
- exit(EXIT_FAILURE);
- }
- if (flags != (FL_SIZE_SPEC|FL_DAYS_SPEC) &&
- flags != FL_DAYS_SPEC &&
- flags != FL_RATE_SPEC) {
- syslog(LOG_NOTICE,
- "%s:%d: should specify frequency "
- "or rate, not both", conf_file,
- linenum);
- exit(EXIT_FAILURE);
- }
- numdisks++;
- }
- fclose(fp);
-
- if (numdisks == 0) {
- syslog(LOG_NOTICE, "no disks specified");
- exit(EXIT_FAILURE);
- }
-
- /*
- * Step 2: expand any dp->device == "*" entries. onumdisks is used
- * so that we don't keep checking dp->device for the new disks as
- * they're added, since that's pointless.
- */
- onumdisks = numdisks;
- for (dp = disks; dp < disks + onumdisks; dp++) {
- if (strcmp(dp->device, "*") == 0) {
- for (np = np0 = getdisknames(skip, numskip); *np != NULL; np++) {
- odisks = disks;
- if ((disks = reallocf(disks,
- (numdisks + 1) * sizeof (*disks))) == NULL) {
- syslog(LOG_NOTICE,
- "reallocf failure: %m");
- exit(EXIT_FAILURE);
- }
-
- /* "disks" pointer may have changed. */
- dp = disks + (dp - odisks);
-
- disks[numdisks].rate = dp->rate;
- disks[numdisks].size = dp->size;
- disks[numdisks].days = dp->days;
- disks[numdisks].interval = dp->interval;
- disks[numdisks].next = 0;
- disks[numdisks].device = *np;
- numdisks++;
- }
-
- /* Don't free the individual pointers, since they're
- * used as new dp->device entries.
- */
- free(np0);
- }
- }
-
- /* Step 3: open all the disks and set the rate to check at
- * appropriately. Use "onumdisks" because numdisks changes within
- * the loop.
- */
- onumdisks = numdisks;
- for (dp = disks; dp < disks + onumdisks; dp++) {
- if (strcmp(dp->device, "*") == 0) {
- numdisks--;
- continue;
- }
-
- if ((dp->fd = open(dp->device, O_RDONLY)) < 0) {
- syslog(LOG_NOTICE, "open %s failed: %m", dp->device);
- numdisks--;
- continue;
- }
-
- dp->errors = 0;
-
- /*
- * Set the rate appropriately. We always read 64KB blocks,
- * at a rate of 1 block per n seconds, where we adjust n to
- * make the overall rate close to what the user specified.
- */
- if (dp->size < 0)
- getdisksize(dp);
- if (dp->rate < 0)
- dp->rate = dp->size / (dp->days * 86400);
-
- if (dp->rate == 0)
- /* paranoia, should never really happen */
- dp->interval = READ_SIZE;
- else
- dp->interval = READ_SIZE / dp->rate;
- }
-
- if (numdisks == 0) {
- syslog(LOG_NOTICE, "no disks usable");
- exit(EXIT_FAILURE);
- }
-
- /* Add a final entry with dp->device == NULL to end the array. */
- if ((disks = reallocf(disks,
- (onumdisks + 1) * sizeof (*disks))) == NULL) {
- syslog(LOG_NOTICE, "reallocf failure: %m");
- exit(EXIT_FAILURE);
- }
- disks[onumdisks].device = NULL;
-
- return (disks);
-}
-
-/*
- * Read in the specified disk's size from the disklabel.
- */
-void
-getdisksize(struct disk *dp) {
- struct disklabel label;
-
- if (ioctl(dp->fd, DIOCGDINFO, &label) < 0) {
- syslog(LOG_NOTICE, "DIOCGDINFO on %s failed: %m",
- dp->device);
- exit(EXIT_FAILURE);
- }
-
- dp->secsize = label.d_secsize;
- dp->size = (off_t)label.d_secperunit * label.d_secsize;
-
- if (label.d_secsize != 512)
- syslog(LOG_NOTICE,
- "%s has %d byte sectors, may cause minor problems",
- dp->device, label.d_secsize);
-}
-
-off_t
-dseek(struct disk *dp, off_t offset, int whence) {
- off_t n;
-
- if ((n = lseek(dp->fd, offset, whence)) == -1) {
- syslog(LOG_NOTICE, "seek failure on %s: %m", dp->device);
- close(dp->fd);
- dp->fd = -1;
- }
- return (n);
-}
-
-/*
- * Attempt to get a list of all disk names using the `kern.disks' sysctl
- * variable. An NULL terminated list of pointers to these disks' pathnames
- * is returned.
- */
-char **
-getdisknames(char **skip, int numskip) {
- char *string, *field;
- size_t size, numdisks;
- char **disks;
- int i;
-
- if (sysctlbyname("kern.disks", NULL, &size, NULL, 0) != 0 &&
- errno != ENOMEM) {
- syslog(LOG_NOTICE, "sysctl kern.disks failure: %m");
- exit(EXIT_FAILURE);
- }
- if ((string = malloc(size)) == NULL) {
- syslog(LOG_NOTICE, "malloc failure: %m");
- exit(EXIT_FAILURE);
- }
- if (sysctlbyname("kern.disks", string, &size, NULL, 0) != 0) {
- syslog(LOG_NOTICE, "sysctl kern.disks failure: %m");
- exit(EXIT_FAILURE);
- }
-
- disks = NULL;
- numdisks = 0;
- while ((field = strsep(&string, " ")) != NULL) {
- /* check for disks we ignore */
- for (i = 0; i < numskip; i++)
- if (strncmp(field, skip[i], strlen(skip[i])) == 0)
- break;
- if (i < numskip)
- continue;
-
- if ((disks = reallocf(disks,
- (numdisks + 1) * sizeof (*disks))) == NULL) {
- syslog(LOG_NOTICE, "reallocf failure: %m");
- exit(EXIT_FAILURE);
- }
- if (asprintf(&disks[numdisks],
- "%s%s", _PATH_DEV, field) < 0) {
- syslog(LOG_NOTICE, "asprintf failure: %m");
- exit(EXIT_FAILURE);
- }
- numdisks++;
- }
-
- if ((disks = reallocf(disks,
- (numdisks + 1) * sizeof (*disks))) == NULL) {
- syslog(LOG_NOTICE, "strdup failure: %m");
- exit(EXIT_FAILURE);
- }
- disks[numdisks] = NULL;
-
- free(string);
- return (disks);
-}
-
-void
-sighup(int sig) {
-
- sig = sig;
- got_sighup = 1;
-}
-
-void
-sigterm(int sig) {
-
- sig = sig;
- got_sigterm = 1;
-}
-
-void
-usage(void) {
-
- fprintf(stderr,
- "usage: diskcheckd [-d] [-f conf_file] [-o save_file]\n");
- exit(EXIT_FAILURE);
-}
OpenPOWER on IntegriCloud