executor/src/checkpoint.c

265 lines
5.7 KiB
C

/* Copyright 1997 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_checkpoint[] =
"$Id: checkpoint.c 63 2004-12-24 18:19:43Z ctm $";
#endif
#if defined (STANDALONE_TEST)
#warning do not check this in
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char boolean_t;
typedef unsigned int uint32;
#define PUBLIC
#define PRIVATE static
PRIVATE uint32 ROMlib_macdrives;
PRIVATE uint32 ROMlib_dosdrives;
enum { FALSE, TRUE };
#endif
#include "rsys/common.h"
#include "rsys/stdfile.h"
#include "rsys/option.h"
#include "rsys/checkpoint.h"
#if defined (MSDOS) || defined (CYGWIN32)
#if defined (CYGWIN32)
#include "winfs.h"
#endif
PRIVATE boolean_t checkpointing_p = TRUE;
PUBLIC checkpoint_t *checkpointp; /* globals are bad, but we use one in
this case because checkpointing is
effectively a global issue currently
and we don't want to modify the various
routines that we checkpoint to take
an additional argument */
PRIVATE uint32
extract_bad_drives_from_string (const char *opt, const char *str)
{
int len;
char *p;
uint32 good_drives;
uint32 retval;
while (*str != ' ')
++str;
++str;
len = strspn (str, "abcdefghijklmnopqrstuvwxyz-");
p = alloca (len+1);
memcpy (p, str, len);
p[len] = 0;
good_drives = parse_drive_opt (opt, p);
retval = ~good_drives & ((1 << 26)-1);
return retval;
}
PUBLIC checkpoint_t *
checkpoint_init (void)
{
checkpoint_t *retval;
FILE *fp;
retval = malloc (sizeof *retval);
memset (retval, 0, sizeof *retval);
fp = executor_dir_fopen (CHECKPOINT_FILE, "r");
if (fp)
{
char buf[1024], *p;
int nread;
nread = fread (buf, 1, sizeof buf-1, fp);
fclose (fp);
buf[sizeof buf -1] = 0;
if (strstr (buf, "-nosound"))
retval->sound_fails = TRUE;
if (strstr (buf, "-skipaspi"))
retval->aspi_fails = TRUE;
p = strstr (buf, "-macdrives ");
if (p)
retval->bad_macdrives
= extract_bad_drives_from_string ("macdrives", p);
p = strstr (buf, "-dosdrives ");
if (p)
retval->bad_dosdrives
= extract_bad_drives_from_string ("dosdrives", p);
}
return retval;
}
PRIVATE void
write_drive_string (FILE *fp, uint32 drive)
{
drive &= (1 << 26)-1; /* only represent A-Z */
if (!drive)
fprintf (fp, "\"\"\n");
else
{
int drive_bit;
drive_bit = 0;
while (drive)
{
while ((drive & (1 << drive_bit)) == 0)
drive_bit++;
if ((drive & (1 << (drive_bit+1))) == 0)
{
fprintf (fp, "%c", 'a' + drive_bit);
drive &= ~(1 << drive_bit);
}
else
{
if ((drive & (1 << (drive_bit+2))) == 0)
{
fprintf (fp, "%c%c", 'a' + drive_bit, 'a' + drive_bit + 1);
drive &= ~((1 << drive_bit) | (1 << (drive_bit+1)));
}
else
{
int last_good_bit;
uint32 mask;
last_good_bit = drive_bit+2;
mask = (1 << drive_bit) | (1 << (drive_bit+1))
| (1 << (drive_bit+2));
while ((drive & (1 << (last_good_bit+1))) != 0)
{
++last_good_bit;
mask |= (1 << last_good_bit);
}
fprintf (fp, "%c-%c", 'a' + drive_bit, 'a' + last_good_bit);
drive &= ~mask;
}
}
}
fprintf (fp, "\n");
}
}
#define CHECKPOINT_PREAMBLE \
"# This file was created because Executor found a problem while it was\n" \
"# probing your system. The lines in this file that don't start with\n" \
"# a '#' are commands that Executor uses to bypass the failing subsystems.\n" \
"#\n" \
"# DO NOT ALTER THIS FILE unless you know what you're doing and even then\n" \
"# make sure you make a backup, first.\n"
PRIVATE void
write_checkpoint_file (checkpoint_t *cp)
{
FILE *fp;
if (!(cp->sound_fails
|| cp->aspi_fails
|| cp->bad_macdrives
|| cp->bad_dosdrives))
executor_dir_remove (CHECKPOINT_FILE);
else
{
fp = executor_dir_fopen (CHECKPOINT_FILE, "w");
if (fp)
{
fprintf (fp, CHECKPOINT_PREAMBLE);
if (cp->sound_fails)
fprintf (fp, "-nosound\n");
if (cp->aspi_fails)
fprintf (fp, "-skipaspi\n");
if (cp->bad_macdrives)
{
uint32 macdrives;
macdrives = ROMlib_macdrives ? ROMlib_macdrives : ~0;
macdrives &= ~cp->bad_macdrives;
fprintf (fp, "-macdrives ");
write_drive_string (fp, macdrives);
}
if (cp->bad_dosdrives)
{
uint32 dosdrives;
dosdrives = ROMlib_dosdrives ? ROMlib_dosdrives : ~0;
dosdrives &= ~cp->bad_dosdrives;
fprintf (fp, "-dosdrives ");
write_drive_string (fp, dosdrives);
}
fclose (fp);
sync ();
}
}
}
PUBLIC void
checkpoint_sound (checkpoint_t *cp, checkpoint_option option)
{
if (checkpointing_p && cp)
{
cp->sound_fails = option == begin;
write_checkpoint_file (cp);
}
}
PUBLIC void
checkpoint_aspi (checkpoint_t *cp, checkpoint_option option)
{
if (checkpointing_p && cp)
{
cp->aspi_fails = option == begin;
write_checkpoint_file (cp);
}
}
PUBLIC void
checkpoint_macdrive (checkpoint_t *cp, checkpoint_option option, uint32 drive)
{
if (checkpointing_p && cp)
{
if (option == begin)
cp->bad_macdrives |= drive;
else
cp->bad_macdrives &= ~drive;
write_checkpoint_file (cp);
}
}
PUBLIC void
checkpoint_dosdrives (checkpoint_t *cp, checkpoint_option option, uint32 drive)
{
if (checkpointing_p && cp)
{
if (option == begin)
cp->bad_dosdrives |= drive;
else
cp->bad_dosdrives &= ~drive;
write_checkpoint_file (cp);
}
}
PUBLIC void
disable_checkpointing (void)
{
checkpointing_p = FALSE;
}
#if defined (STANDALONE_TEST)
PUBLIC int
main (void)
{
checkpoint_t *cp;
cp = checkpoint_init ();
return 0;
}
#endif
#endif