* Ported to Linux's Second Extended File System as part of the
* dump and restore backup suit
* Remy Card <card@Linux.EU.Org>, 1994-1997
- * Stelian Pop <pop@cybercable.fr>, 1999
- *
+ * Stelian Pop <stelian@popies.net>, 1999-2000
+ * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
*/
/*-
*/
#ifndef lint
-#if 0
-static char sccsid[] = "@(#)optr.c 8.2 (Berkeley) 1/6/94";
-#endif
static const char rcsid[] =
- "$Id: optr.c,v 1.2 1999/10/11 12:53:22 stelian Exp $";
+ "$Id: optr.c,v 1.31 2002/02/04 11:18:45 stelian Exp $";
#endif /* not lint */
+#include <config.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/time.h>
+#include <time.h>
#include <errno.h>
#include <fstab.h>
#include <stdarg.h>
#include <unistd.h>
#include <utmp.h>
+#include <sys/stat.h>
#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
#include <linux/ext2_fs.h>
+#endif
#include <ext2fs/ext2fs.h>
#include <bsdcompat.h>
#include <signal.h>
#include "dump.h"
#include "pathnames.h"
+#include "bylabel.h"
-void alarmcatch __P((/* int, int */));
+static void alarmcatch __P((int));
int datesort __P((const void *, const void *));
-static void sendmes __P((char *, char *));
+static void sendmes __P((const char *, const char *));
+
+/* List of filesystem types that we can dump (same ext2 on-disk format) */
+static char *fstypes[] = { "ext2", "ext3", "InterMezzo", NULL };
/*
* Query the operator; This previously-fascist piece of code
* that dump needs attention.
*/
static int timeout;
-static char *attnmessage; /* attention message */
+static const char *attnmessage; /* attention message */
int
-query(question)
- char *question;
+query(const char *question)
{
char replybuffer[64];
int back, errcount;
FILE *mytty;
+ time_t firstprompt, when_answered;
+
+ if (qflag) {
+ msg("%s - forced abort\n", question);
+ dumpabort(0);
+ /* NOTREACHED */
+ }
+
+ firstprompt = time(NULL);
if ((mytty = fopen(_PATH_TTY, "r")) == NULL)
quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno));
attnmessage = question;
timeout = 0;
- alarmcatch();
+ alarmcatch(0);
back = -1;
errcount = 0;
do {
if (signal(SIGALRM, sig) == SIG_IGN)
signal(SIGALRM, SIG_IGN);
(void) fclose(mytty);
+ when_answered = time(NULL);
+ /*
+ * Adjust the base for time estimates to ignore time we spent waiting
+ * for operator input.
+ */
+ if (tstart_writing != 0)
+ tstart_writing += (when_answered - firstprompt);
return(back);
}
-char lastmsg[100];
+char lastmsg[BUFSIZ];
/*
* Alert the console operator, and enable the alarm clock to
* sleep for 2 minutes in case nobody comes to satisfy dump
*/
-void
-alarmcatch()
+static void
+alarmcatch(int signo)
{
+ int save_errno = errno;
if (notify == 0) {
if (timeout == 0)
(void) fprintf(stderr,
signal(SIGALRM, alarmcatch);
(void) alarm(120);
timeout = 1;
+ errno = save_errno;
}
/*
* Here if an inquisitive operator interrupts the dump program
*/
void
-interrupt(signo)
- int signo;
+interrupt(int signo)
{
msg("Interrupt received.\n");
if (query("Do you want to abort dump?"))
* Get the names from the group entry "operator" to notify.
*/
void
-set_operators()
+set_operators(void)
{
if (!notify) /*not going to notify*/
return;
* that the process control groups are not messed up
*/
void
-broadcast(message)
- char *message;
+broadcast(const char *message)
{
time_t clock;
FILE *f_utmp;
return;
}
- clock = time((time_t *)0);
+ clock = time(NULL);
localclock = localtime(&clock);
if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
}
static void
-sendmes(tty, message)
- char *tty, *message;
+sendmes(const char *tty, const char *message)
{
char t[MAXPATHLEN], buf[BUFSIZ];
- register char *cp;
+ const char *cp;
int lmsg = 1;
FILE *f_tty;
if (*cp == '\0') {
if (lmsg) {
cp = message;
- if (*cp == '\0')
+ if (!(cp && *cp != '\0'))
break;
lmsg = 0;
} else
time_t tschedule = 0;
void
-timeest()
+timeest(void)
{
- time_t tnow, deltat;
+ time_t tnow = time(NULL);
- (void) time((time_t *) &tnow);
if (tnow >= tschedule) {
+ char *buf = mktimeest(tnow);
tschedule = tnow + 300;
- if (blockswritten < 500)
- return;
- deltat = tstart_writing - tnow +
- (1.0 * (tnow - tstart_writing))
- / blockswritten * tapesize;
- msg("%3.2f%% done, finished in %d:%02d\n",
- (blockswritten * 100.0) / tapesize,
- deltat / 3600, (deltat % 3600) / 60);
+ if (buf) {
+ fprintf(stderr, " DUMP: ");
+ fwrite(buf, strlen(buf), 1, stderr);
+ fflush(stderr);
+ }
}
}
void
-#if __STDC__
+#ifdef __STDC__
msg(const char *fmt, ...)
#else
msg(fmt, va_alist)
#ifdef TDEBUG
(void) fprintf(stderr, "pid=%d ", getpid());
#endif
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
(void) fflush(stdout);
(void) fflush(stderr);
- (void) vsprintf(lastmsg, fmt, ap);
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) vsnprintf(lastmsg, sizeof(lastmsg), fmt, ap);
va_end(ap);
}
void
-#if __STDC__
+#ifdef __STDC__
msgtail(const char *fmt, ...)
#else
msgtail(fmt, va_alist)
#endif
{
va_list ap;
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
}
void
-#if __STDC__
+#ifdef __STDC__
quit(const char *fmt, ...)
#else
quit(fmt, va_alist)
#ifdef TDEBUG
(void) fprintf(stderr, "pid=%d ", getpid());
#endif
-#if __STDC__
+#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
* we don't actually do it
*/
-struct fstab *
-allocfsent(fs)
- register struct fstab *fs;
+static struct fstab *
+allocfsent(struct fstab *fs)
{
- register struct fstab *new;
+ struct fstab *new;
new = (struct fstab *)malloc(sizeof (*fs));
- if (new == NULL ||
- (new->fs_file = strdup(fs->fs_file)) == NULL ||
+ if (new == NULL)
+ quit("%s\n", strerror(errno));
+ if (strlen(fs->fs_file) > 1 && fs->fs_file[strlen(fs->fs_file) - 1] == '/')
+ fs->fs_file[strlen(fs->fs_file) - 1] = '\0';
+ if ((new->fs_file = strdup(fs->fs_file)) == NULL ||
(new->fs_type = strdup(fs->fs_type)) == NULL ||
+ (new->fs_vfstype = strdup(fs->fs_vfstype)) == NULL ||
(new->fs_spec = strdup(fs->fs_spec)) == NULL)
quit("%s\n", strerror(errno));
new->fs_passno = fs->fs_passno;
struct pfstab {
struct pfstab *pf_next;
+ struct dumpdates *pf_dd;
struct fstab *pf_fstab;
};
static struct pfstab *table;
void
-getfstab()
+getfstab(void)
{
- register struct fstab *fs;
- register struct pfstab *pf;
+ struct fstab *fs;
+ struct pfstab *pf;
+ struct pfstab *pfold = NULL;
if (setfsent() == 0) {
msg("Can't open %s for dump table information: %s\n",
strcmp(fs->fs_type, FSTAB_RQ))
continue;
fs = allocfsent(fs);
+ fs->fs_passno = 0;
if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL)
quit("%s\n", strerror(errno));
pf->pf_fstab = fs;
- pf->pf_next = table;
- table = pf;
+ pf->pf_next = NULL;
+
+ /* keep table in /etc/fstab order for use with -w and -W */
+ if (pfold) {
+ pfold->pf_next = pf;
+ pfold = pf;
+ } else
+ pfold = table = pf;
+
}
(void) endfsent();
}
* The file name can omit the leading '/'.
*/
struct fstab *
-fstabsearch(key)
- char *key;
+fstabsearch(const char *key)
{
- register struct pfstab *pf;
- register struct fstab *fs;
- char *rn;
+ struct pfstab *pf;
+ struct fstab *fs;
+ const char *rn;
for (pf = table; pf != NULL; pf = pf->pf_next) {
fs = pf->pf_fstab;
#ifdef __linux__
struct fstab *
-fstabsearchdir(key, directory)
- char *key;
- char *directory;
+fstabsearchdir(const char *key, char *directory)
{
- register struct pfstab *pf;
- register struct fstab *fs;
- register struct fstab *found_fs = NULL;
+ struct pfstab *pf;
+ struct fstab *fs;
+ struct fstab *found_fs = NULL;
unsigned int size = 0;
+ struct stat buf;
+
+ if (stat(key, &buf) == 0 && S_ISBLK(buf.st_mode))
+ return NULL;
for (pf = table; pf != NULL; pf = pf->pf_next) {
fs = pf->pf_fstab;
if (strlen(fs->fs_file) > size &&
- strlen(key) > strlen(fs->fs_file) + 2 &&
+ strlen(key) > strlen(fs->fs_file) &&
strncmp(fs->fs_file, key, strlen(fs->fs_file)) == 0 &&
(key[strlen(fs->fs_file)] == '/' ||
fs->fs_file[strlen(fs->fs_file) - 1] == '/')) {
}
#endif
+static void
+print_wmsg(char arg, int dumpme, const char *dev, int level,
+ const char *mtpt, time_t ddate)
+{
+#ifdef FDEBUG
+ printf("checking dev %s: lvl %d, mtpt %s\n", dev, level, mtpt);
+#endif
+ if (!dumpme && arg == 'w')
+ return;
+
+ (void) printf("%c %8s\t(%6s) Last dump: ",
+ dumpme && (arg != 'w') ? '>' : ' ',
+ dev,
+ mtpt ? mtpt : "");
+
+ /*
+ * Check ddate > 365 to avoid issues with fs in stab but not dumpdates.
+ * Not a problem, because ddate is in seconds since the epoch anyways.
+ */
+ if (ddate > 365) {
+ char *date, *d;
+
+ date = (char *)ctime(&ddate);
+ d = strchr(date, '\n');
+ if (d) *d = '\0';
+ printf("Level %c, Date %s\n", level, date);
+ } else
+ printf("never\n");
+}
+
/*
* Tell the operator what to do
*/
void
-lastdump(arg)
- char arg; /* w ==> just what to do; W ==> most recent dumps */
+lastdump(char arg) /* w ==> just what to do; W ==> most recent dumps */
{
- register int i;
- register struct fstab *dt;
- register struct dumpdates *dtwalk;
- char *lastname, *date;
- int dumpme;
+ struct pfstab *pf;
time_t tnow;
- (void) time(&tnow);
+ tnow = time(NULL);
getfstab(); /* /etc/fstab input */
- initdumptimes(); /* /etc/dumpdates input */
- qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
+ initdumptimes(0); /* dumpdates input */
+ if (ddatev == NULL && table == NULL) {
+ (void) printf("No %s or %s file found\n",
+ _PATH_FSTAB, _PATH_DUMPDATES);
+ return;
+ }
if (arg == 'w')
(void) printf("Dump these file systems:\n");
else
(void) printf("Last dump(s) done (Dump '>' file systems):\n");
- lastname = "??";
- ITITERATE(i, dtwalk) {
- if (strncmp(lastname, dtwalk->dd_name,
- sizeof(dtwalk->dd_name)) == 0)
- continue;
- date = (char *)ctime(&dtwalk->dd_ddate);
- date[16] = '\0'; /* blast away seconds and year */
- lastname = dtwalk->dd_name;
- dt = fstabsearch(dtwalk->dd_name);
- dumpme = (dt != NULL &&
- dt->fs_freq != 0 &&
- dtwalk->dd_ddate < tnow - (dt->fs_freq * 86400));
- if (arg != 'w' || dumpme)
- (void) printf(
- "%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
- dumpme && (arg != 'w') ? '>' : ' ',
- dtwalk->dd_name,
- dt ? dt->fs_file : "",
- dtwalk->dd_level,
- date);
+
+ /* For files in dumpdates, get the last dump level and date */
+ if (ddatev != NULL) {
+ struct dumpdates *dtwalk = NULL;
+ int i;
+ char *lastname;
+
+ qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
+
+ lastname = "??";
+ ITITERATE(i, dtwalk) {
+ struct fstab *dt;
+ if (strncmp(lastname, dtwalk->dd_name,
+ sizeof(dtwalk->dd_name)) == 0)
+ continue;
+ lastname = dtwalk->dd_name;
+ if ((dt = dtwalk->dd_fstab) != NULL) {
+ /* Overload fs_freq as dump level and
+ * fs_passno as date, because we can't
+ * change struct fstab format.
+ * A positive fs_freq means this
+ * filesystem needs to be dumped.
+ */
+ dt->fs_passno = dtwalk->dd_ddate;
+ if (dt->fs_freq > 0 && (dtwalk->dd_ddate <
+ tnow - (dt->fs_freq * 86400)))
+ dt->fs_freq = dtwalk->dd_level;
+ else
+ dt->fs_freq = -dtwalk->dd_level;
+#ifdef FDEBUG
+ printf("%s fs_freq set to %d\n", lastname,
+ dt->fs_freq);
+#endif
+ }
+ }
+ }
+
+ /* print in /etc/fstab order only those filesystem types we can dump */
+ for (pf = table; pf != NULL; pf = pf->pf_next) {
+ struct fstab *dt = pf->pf_fstab;
+ char **type;
+
+ for (type = fstypes; *type != NULL; type++) {
+ if (strncmp(dt->fs_vfstype, *type,
+ sizeof(dt->fs_vfstype)) == 0) {
+ const char *disk = get_device_name(dt->fs_spec);
+ print_wmsg(arg, dt->fs_freq > 0,
+ disk ? disk : dt->fs_spec,
+ dt->fs_freq < 0 ? -dt->fs_freq :
+ dt->fs_freq,
+ dt->fs_file,
+ dt->fs_passno);
+ }
+ }
+ }
+
+ /* print in /etc/dumpdates order if not in /etc/fstab */
+ if (ddatev != NULL) {
+ struct dumpdates *dtwalk = NULL;
+ char *lastname;
+ int i;
+
+ lastname = "??";
+ ITITERATE(i, dtwalk) {
+ if (strncmp(lastname, dtwalk->dd_name,
+ sizeof(dtwalk->dd_name)) == 0 ||
+ dtwalk->dd_fstab != NULL)
+ continue;
+ lastname = dtwalk->dd_name;
+ print_wmsg(arg, 0, dtwalk->dd_name,
+ dtwalk->dd_level, NULL, dtwalk->dd_ddate);
+ }
}
}
int
-datesort(a1, a2)
- const void *a1, *a2;
+datesort(const void *a1, const void *a2)
{
struct dumpdates *d1 = *(struct dumpdates **)a1;
struct dumpdates *d2 = *(struct dumpdates **)a2;