#include <errno.h>
#include "dump.h"
time_t *tschedule;
static unsigned int timeout;
static char *attnmessage, *saveattn;
static void alarmcatch(int);
static int idatesort(const void *, const void *);
#ifdef DEBUG
extern int xflag;
#endif
int
query(char *question)
{
int def = -1;
while (def == -1)
def = query_once(question, -1);
return (def);
}
static int in_query_once;
static jmp_buf sjalarmbuf;
static int
addem(char *s)
{
int total = 0;
if (s == (char *)NULL)
return (total);
while (*s)
total += *s++;
return (total);
}
int
query_once(char *question, int def)
{
static char *lastmsg;
static int lastmsgsum;
int msgsum;
char replybuffer[BUFSIZ];
int back;
time32_t timeclockstate;
pollfd_t pollset;
struct sigvec sv;
if (question == NULL) {
lastmsg = (char *)NULL;
lastmsgsum = 0;
return (0);
}
attnmessage = question;
msgsum = addem(question);
if (lastmsg != question || lastmsgsum != msgsum) {
timeout = 0;
if (telapsed && tstart_writing)
*telapsed += time((time_t *)0) - *tstart_writing;
lastmsg = question;
lastmsgsum = msgsum;
}
timeclockstate = timeclock((time_t)0);
if (setjmp(sjalarmbuf) != 0) {
if (def != -1) {
if (def)
msgtail(gettext("YES\n"));
else
msgtail(gettext("NO\n"));
}
back = def;
goto done;
}
alarmcatch(SIGALRM);
in_query_once = 1;
pollset.fd = -1;
pollset.events = 0;
pollset.revents = 0;
if (isatty(fileno(stdin))) {
pollset.fd = fileno(stdin);
pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
} else {
dumpabort();
}
for (;;) {
if (poll(&pollset, 1, -1) < 0) {
if (errno == EINTR)
continue;
perror("poll(stdin)");
dumpabort();
}
if (pollset.revents == 0)
continue;
if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) {
if (ferror(stdin)) {
clearerr(stdin);
continue;
} else {
dumpabort();
}
}
timeout = 0;
if (strcasecmp(replybuffer, gettext("yes\n")) == 0) {
back = 1;
lastmsg = (char *)NULL;
lastmsgsum = 0;
goto done;
} else if (strcasecmp(replybuffer, gettext("no\n")) == 0) {
back = 0;
lastmsg = (char *)NULL;
lastmsgsum = 0;
goto done;
} else {
msg(gettext("\"yes\" or \"no\"?\n"));
in_query_once = 0;
alarmcatch(SIGALRM);
in_query_once = 1;
}
}
done:
(void) alarm(0);
attnmessage = NULL;
sv.sv_handler = sigAbort;
sv.sv_flags = SA_RESTART;
(void) sigemptyset(&sv.sa_mask);
(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
if (tstart_writing)
(void) time(tstart_writing);
(void) timeclock(timeclockstate);
in_query_once = 0;
return (back);
}
static void
alarmcatch(int signal __unused)
{
struct sigvec sv;
if (in_query_once) {
longjmp(sjalarmbuf, 1);
}
if (timeout) {
msgtail("\n");
}
timeout += 120;
msg(gettext("NEEDS ATTENTION: %s"), attnmessage);
sv.sv_handler = alarmcatch;
sv.sv_flags = SA_RESTART;
(void) sigemptyset(&sv.sa_mask);
(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
(void) alarm(timeout);
}
void
interrupt(int sig)
{
if (!saveattn) {
saveattn = attnmessage;
}
msg(gettext("Interrupt received.\n"));
if (query(gettext(
"Do you want to abort dump?: (\"yes\" or \"no\") "))) {
dumpabort();
}
if (saveattn) {
attnmessage = saveattn;
saveattn = NULL;
alarmcatch(SIGALRM);
}
}
void
broadcast(char *message)
{
time_t clock;
pid_t pid;
int saverr;
int fildes[2];
FILE *wall;
struct tm *localclock;
if (!notify)
return;
if (pipe(fildes) < 0) {
saverr = errno;
msg(gettext("pipe: %s\n"), strerror(saverr));
return;
}
switch (pid = fork()) {
case -1:
return;
case 0:
close(fildes[0]);
if (dup2(fildes[1], 0) < 0) {
saverr = errno;
msg(gettext("dup2: %s\n"), strerror(saverr));
exit(1);
}
execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL);
saverr = errno;
msg(gettext("execl: %s\n"), strerror(saverr));
exit(1);
default:
break;
}
close(fildes[1]);
wall = fdopen(fildes[0], "r+");
if (wall == (FILE *)NULL) {
saverr = errno;
msg(gettext("fdopen: %s\n"), strerror(saverr));
return;
}
clock = time((time_t *)0);
localclock = localtime(&clock);
(void) fprintf(wall, gettext(
"\n\007\007\007Message from the dump program to all operators at \
%d:%02d ...\n\n%s"),
localclock->tm_hour, localclock->tm_min, message);
fclose(wall);
while (wait((int *)0) != pid) {
continue;
}
}
#define EST_SEC 600
void
timeest(int force, int blkswritten)
{
time_t tnow, deltat;
char *msgp;
if (tschedule == NULL)
return;
if (*tschedule == 0)
*tschedule = time((time_t *)0) + EST_SEC;
(void) time(&tnow);
if ((force || tnow >= *tschedule) && blkswritten) {
*tschedule = tnow + EST_SEC;
if (!force && blkswritten < 50 * ntrec)
return;
deltat = (*telapsed + (tnow - *tstart_writing))
* ((double)esize / blkswritten - 1.0);
msgp = gettext("%3.2f%% done, finished in %d:%02d\n");
msg(msgp, (blkswritten*100.0)/esize,
deltat/3600, (deltat%3600)/60);
}
}
#include <stdarg.h>
void
msg(const char *fmt, ...)
{
char buf[1024], *cp;
size_t size;
va_list args;
va_start(args, fmt);
(void) strcpy(buf, " DUMP: ");
cp = &buf[strlen(buf)];
#ifdef TDEBUG
(void) sprintf(cp, "pid=%d ", getpid());
cp = &buf[strlen(buf)];
#endif
size = ((size_t)sizeof (buf)) - (size_t)(cp - buf);
(void) vsnprintf(cp, size, fmt, args);
(void) fputs(buf, stderr);
(void) fflush(stdout);
(void) fflush(stderr);
va_end(args);
}
void
msgtail(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
(void) vfprintf(stderr, fmt, args);
va_end(args);
}
#define MINUTES(x) ((x) * 60)
void
lastdump(int arg)
{
char *lastname;
char *date;
int i;
time_t tnow, ddate;
struct mntent *dt;
int dumpme = 0;
struct idates *itwalk;
(void) time(&tnow);
mnttabread();
inititimes();
if (arg == 'w')
(void) fprintf(stdout, gettext("Dump these file systems:\n"));
else
(void) fprintf(stdout, gettext(
"Last dump(s) done (Dump '>' file systems):\n"));
if (idatev != NULL) {
qsort((char *)idatev, nidates, sizeof (*idatev), idatesort);
lastname = "??";
ITITERATE(i, itwalk) {
if (strncmp(lastname, itwalk->id_name,
sizeof (itwalk->id_name)) == 0)
continue;
ddate = itwalk->id_ddate;
date = (char *)ctime(&ddate);
date[16] = '\0';
lastname = itwalk->id_name;
dt = mnttabsearch(itwalk->id_name, 0);
if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) {
dumpme = 1;
}
if ((arg == 'w') && dumpme) {
(void) printf(gettext("%8s\t(%6s)\n"),
itwalk->id_name, dt ? dt->mnt_dir : "");
}
if (arg == 'W') {
(void) printf(gettext(
"%c %8s\t(%6s) Last dump: Level %c, Date %s\n"),
dumpme ? '>' : ' ',
itwalk->id_name,
dt ? dt->mnt_dir : "",
(uchar_t)itwalk->id_incno,
date);
}
dumpme = 0;
}
}
}
static int
idatesort(const void *v1, const void *v2)
{
struct idates **p1 = (struct idates **)v1;
struct idates **p2 = (struct idates **)v2;
int diff;
diff = strcoll((*p1)->id_name, (*p2)->id_name);
if (diff == 0) {
if ((*p1)->id_ddate > (*p2)->id_ddate)
diff = -1;
else if ((*p1)->id_ddate < (*p2)->id_ddate)
diff = 1;
}
return (diff);
}