1995-04-27 12:50:35 +00:00
|
|
|
/*
|
|
|
|
* The new sysinstall program.
|
|
|
|
*
|
|
|
|
* This is probably the last program in the `sysinstall' line - the next
|
|
|
|
* generation being essentially a complete rewrite.
|
|
|
|
*
|
1999-01-08 09:13:00 +00:00
|
|
|
* $Id: system.c,v 1.86 1999/01/08 00:14:22 jkh Exp $
|
1995-04-27 12:50:35 +00:00
|
|
|
*
|
|
|
|
* Jordan Hubbard
|
|
|
|
*
|
|
|
|
* My contributions are in the public domain.
|
|
|
|
*
|
|
|
|
* Parts of this file are also blatently stolen from Poul-Henning Kamp's
|
1995-05-19 16:58:58 +00:00
|
|
|
* previous version of sysinstall, and as such fall under his "BEERWARE license"
|
|
|
|
* so buy him a beer if you like it! Buy him a beer for me, too!
|
|
|
|
* Heck, get him completely drunk and send me pictures! :-)
|
1995-04-27 12:50:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sysinstall.h"
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/reboot.h>
|
1995-05-05 23:47:47 +00:00
|
|
|
#include <machine/console.h>
|
1995-04-27 12:50:35 +00:00
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
1999-01-08 09:13:00 +00:00
|
|
|
#include <sys/stat.h>
|
1995-04-27 12:50:35 +00:00
|
|
|
|
1996-07-05 08:36:02 +00:00
|
|
|
|
|
|
|
/* Where we stick our temporary expanded doc file */
|
1999-01-08 09:13:00 +00:00
|
|
|
#define DOC_TMP_DIR "/tmp/.doc"
|
|
|
|
#define DOC_TMP_FILE "/tmp/.doc/doc.tmp"
|
1996-07-05 08:36:02 +00:00
|
|
|
|
1996-12-29 05:51:40 +00:00
|
|
|
static pid_t ehs_pid;
|
|
|
|
|
1995-05-05 23:47:47 +00:00
|
|
|
/*
|
|
|
|
* Handle interrupt signals - this probably won't work in all cases
|
|
|
|
* due to our having bogotified the internal state of dialog or curses,
|
|
|
|
* but we'll give it a try.
|
|
|
|
*/
|
1995-04-27 12:50:35 +00:00
|
|
|
static void
|
|
|
|
handle_intr(int sig)
|
|
|
|
{
|
1996-10-01 12:13:29 +00:00
|
|
|
WINDOW *save = savescr();
|
|
|
|
|
1995-05-05 23:47:47 +00:00
|
|
|
if (!msgYesNo("Are you sure you want to abort the installation?"))
|
1997-01-15 08:01:10 +00:00
|
|
|
systemShutdown(-1);
|
1996-10-01 12:13:29 +00:00
|
|
|
else
|
|
|
|
restorescr(save);
|
1995-04-27 12:50:35 +00:00
|
|
|
}
|
|
|
|
|
1996-07-05 08:36:02 +00:00
|
|
|
/* Expand a file into a convenient location, nuking it each time */
|
|
|
|
static char *
|
|
|
|
expand(char *fname)
|
|
|
|
{
|
1998-09-30 11:44:29 +00:00
|
|
|
char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip";
|
|
|
|
|
1999-01-08 09:13:00 +00:00
|
|
|
if (!directory_exists(DOC_TMP_DIR)) {
|
|
|
|
Mkdir(DOC_TMP_DIR);
|
|
|
|
if (chown(DOC_TMP_DIR, 0, 0) < 0)
|
|
|
|
return NULL;
|
|
|
|
if (chmod(DOC_TMP_DIR, S_IRWXU) < 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
unlink(DOC_TMP_FILE);
|
1998-09-30 13:36:53 +00:00
|
|
|
if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE))
|
1996-07-05 08:36:02 +00:00
|
|
|
return NULL;
|
|
|
|
return DOC_TMP_FILE;
|
|
|
|
}
|
|
|
|
|
1995-04-27 12:50:35 +00:00
|
|
|
/* Initialize system defaults */
|
|
|
|
void
|
|
|
|
systemInitialize(int argc, char **argv)
|
|
|
|
{
|
1995-05-19 16:58:58 +00:00
|
|
|
int i;
|
|
|
|
|
1995-04-27 12:50:35 +00:00
|
|
|
signal(SIGINT, SIG_IGN);
|
|
|
|
globalsInit();
|
|
|
|
|
|
|
|
/* Are we running as init? */
|
|
|
|
if (getpid() == 1) {
|
1997-07-31 11:08:47 +00:00
|
|
|
int fd, type;
|
|
|
|
|
|
|
|
RunningAsInit = 1;
|
1995-04-27 12:50:35 +00:00
|
|
|
setsid();
|
1996-09-26 21:07:11 +00:00
|
|
|
close(0);
|
1997-07-31 11:08:47 +00:00
|
|
|
fd = open("/dev/ttyv0", O_RDWR);
|
|
|
|
if (fd == -1)
|
|
|
|
fd = open("/dev/console", O_RDWR); /* fallback */
|
1996-09-26 21:07:11 +00:00
|
|
|
else
|
|
|
|
OnVTY = TRUE;
|
1997-07-31 11:08:47 +00:00
|
|
|
/*
|
|
|
|
* To make _sure_ we're on a VTY and don't have /dev/console switched
|
|
|
|
* away to a serial port or something, attempt to set the cursor appearance.
|
|
|
|
*/
|
|
|
|
type = 0; /* normal */
|
|
|
|
if (OnVTY) {
|
|
|
|
int fd2;
|
|
|
|
|
|
|
|
if ((fd2 = open("/dev/console", O_RDWR)) != -1) {
|
|
|
|
if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) {
|
|
|
|
OnVTY = FALSE;
|
|
|
|
close(fd); close(fd2);
|
|
|
|
open("/dev/console", O_RDWR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
close(fd2);
|
|
|
|
}
|
|
|
|
}
|
1995-06-11 19:33:05 +00:00
|
|
|
close(1); dup(0);
|
|
|
|
close(2); dup(0);
|
1997-07-31 11:08:47 +00:00
|
|
|
printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console");
|
1995-05-26 08:41:52 +00:00
|
|
|
i = ioctl(0, TIOCSCTTY, (char *)NULL);
|
1995-04-27 12:50:35 +00:00
|
|
|
setlogin("root");
|
1995-06-11 19:33:05 +00:00
|
|
|
setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1);
|
1995-04-27 12:50:35 +00:00
|
|
|
setbuf(stdin, 0);
|
|
|
|
setbuf(stderr, 0);
|
|
|
|
}
|
1996-12-11 19:35:26 +00:00
|
|
|
else {
|
|
|
|
char hname[256];
|
|
|
|
|
|
|
|
/* Initalize various things for a multi-user environment */
|
|
|
|
if (!gethostname(hname, sizeof hname))
|
|
|
|
variable_set2(VAR_HOSTNAME, hname);
|
|
|
|
}
|
1995-04-27 12:50:35 +00:00
|
|
|
|
1995-05-10 18:59:51 +00:00
|
|
|
if (set_termcap() == -1) {
|
|
|
|
printf("Can't find terminal entry\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
1995-04-27 12:50:35 +00:00
|
|
|
|
|
|
|
/* XXX - libdialog has particularly bad return value checking */
|
|
|
|
init_dialog();
|
1996-04-25 17:31:27 +00:00
|
|
|
|
1995-04-27 12:50:35 +00:00
|
|
|
/* If we haven't crashed I guess dialog is running ! */
|
|
|
|
DialogActive = TRUE;
|
|
|
|
|
1995-12-07 10:34:59 +00:00
|
|
|
/* Make sure HOME is set for those utilities that need it */
|
|
|
|
if (!getenv("HOME"))
|
|
|
|
setenv("HOME", "/", 1);
|
1995-04-27 12:50:35 +00:00
|
|
|
signal(SIGINT, handle_intr);
|
1999-01-08 09:13:00 +00:00
|
|
|
(void)vsystem("rm -rf %s", DOC_TMP_DIR);
|
1995-04-27 12:50:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close down and prepare to exit */
|
|
|
|
void
|
1996-05-16 11:47:46 +00:00
|
|
|
systemShutdown(int status)
|
1995-04-27 12:50:35 +00:00
|
|
|
{
|
1996-05-16 11:47:46 +00:00
|
|
|
/* If some media is open, close it down */
|
1997-01-15 08:01:10 +00:00
|
|
|
if (status >=0 && mediaDevice)
|
1996-05-16 11:47:46 +00:00
|
|
|
mediaDevice->shutdown(mediaDevice);
|
|
|
|
|
1997-04-28 10:31:14 +00:00
|
|
|
/* write out any changes to rc.conf .. */
|
1997-05-27 18:56:03 +00:00
|
|
|
configRC_conf("/etc/rc.conf");
|
1997-02-10 19:44:08 +00:00
|
|
|
|
1996-05-16 11:47:46 +00:00
|
|
|
/* Shut down the dialog library */
|
1995-04-27 12:50:35 +00:00
|
|
|
if (DialogActive) {
|
|
|
|
end_dialog();
|
|
|
|
DialogActive = FALSE;
|
|
|
|
}
|
1996-05-16 11:47:46 +00:00
|
|
|
|
|
|
|
/* Shut down curses */
|
|
|
|
endwin();
|
|
|
|
|
1999-01-08 09:13:00 +00:00
|
|
|
/* If we have a temporary doc dir lying around, nuke it */
|
|
|
|
(void)vsystem("rm -rf %s", DOC_TMP_DIR);
|
1996-07-05 08:36:02 +00:00
|
|
|
|
1995-04-27 12:50:35 +00:00
|
|
|
/* REALLY exit! */
|
1995-05-26 21:00:43 +00:00
|
|
|
if (RunningAsInit) {
|
|
|
|
/* Put the console back */
|
1995-06-11 19:33:05 +00:00
|
|
|
ioctl(0, VT_ACTIVATE, 2);
|
1999-01-08 00:14:22 +00:00
|
|
|
#ifdef __alpha__
|
|
|
|
reboot(RB_HALT);
|
|
|
|
#else
|
1995-12-07 10:34:59 +00:00
|
|
|
reboot(0);
|
1999-01-08 00:14:22 +00:00
|
|
|
#endif
|
1995-05-26 21:00:43 +00:00
|
|
|
}
|
1995-04-29 19:33:06 +00:00
|
|
|
else
|
1996-05-16 11:47:46 +00:00
|
|
|
exit(status);
|
1995-04-27 12:50:35 +00:00
|
|
|
}
|
|
|
|
|
1995-04-29 19:33:06 +00:00
|
|
|
/* Run some general command */
|
1995-04-27 12:50:35 +00:00
|
|
|
int
|
|
|
|
systemExecute(char *command)
|
|
|
|
{
|
|
|
|
int status;
|
1995-12-07 10:34:59 +00:00
|
|
|
struct termios foo;
|
1995-04-27 12:50:35 +00:00
|
|
|
|
|
|
|
dialog_update();
|
|
|
|
end_dialog();
|
|
|
|
DialogActive = FALSE;
|
1995-12-07 10:34:59 +00:00
|
|
|
if (tcgetattr(0, &foo) != -1) {
|
|
|
|
foo.c_cc[VERASE] = '\010';
|
|
|
|
tcsetattr(0, TCSANOW, &foo);
|
|
|
|
}
|
1996-04-28 20:54:11 +00:00
|
|
|
if (!Fake)
|
|
|
|
status = system(command);
|
|
|
|
else {
|
|
|
|
status = 0;
|
|
|
|
msgDebug("systemExecute: Faked execution of `%s'\n", command);
|
|
|
|
}
|
1995-04-27 12:50:35 +00:00
|
|
|
DialogActive = TRUE;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1995-12-07 10:34:59 +00:00
|
|
|
/* Display a help file in a filebox */
|
1995-04-29 19:33:06 +00:00
|
|
|
int
|
1995-12-07 10:34:59 +00:00
|
|
|
systemDisplayHelp(char *file)
|
1995-04-29 19:33:06 +00:00
|
|
|
{
|
1995-05-01 21:56:32 +00:00
|
|
|
char *fname = NULL;
|
|
|
|
char buf[FILENAME_MAX];
|
1996-04-26 18:19:38 +00:00
|
|
|
int ret = 0;
|
1995-04-29 19:33:06 +00:00
|
|
|
|
1995-05-01 21:56:32 +00:00
|
|
|
fname = systemHelpFile(file, buf);
|
1995-04-29 19:33:06 +00:00
|
|
|
if (!fname) {
|
|
|
|
snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
|
1995-05-01 21:56:32 +00:00
|
|
|
use_helpfile(NULL);
|
|
|
|
use_helpline(NULL);
|
|
|
|
dialog_mesgbox("Sorry!", buf, -1, -1);
|
1996-04-26 18:19:38 +00:00
|
|
|
ret = 1;
|
1995-04-29 19:33:06 +00:00
|
|
|
}
|
|
|
|
else {
|
1995-05-01 21:56:32 +00:00
|
|
|
use_helpfile(NULL);
|
|
|
|
use_helpline(NULL);
|
1995-04-29 19:33:06 +00:00
|
|
|
dialog_textbox(file, fname, LINES, COLS);
|
|
|
|
}
|
1996-04-26 18:19:38 +00:00
|
|
|
return ret;
|
1995-04-29 19:33:06 +00:00
|
|
|
}
|
1995-05-01 21:56:32 +00:00
|
|
|
|
|
|
|
char *
|
|
|
|
systemHelpFile(char *file, char *buf)
|
|
|
|
{
|
|
|
|
if (!file)
|
|
|
|
return NULL;
|
|
|
|
|
1996-07-05 08:36:02 +00:00
|
|
|
snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file);
|
1998-11-03 03:38:56 +00:00
|
|
|
if (file_readable(buf))
|
|
|
|
return expand(buf);
|
|
|
|
snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file);
|
1995-09-18 16:53:06 +00:00
|
|
|
if (file_readable(buf))
|
1996-07-05 08:36:02 +00:00
|
|
|
return expand(buf);
|
1996-05-16 11:47:46 +00:00
|
|
|
snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.hlp", file);
|
1998-11-03 03:38:56 +00:00
|
|
|
if (file_readable(buf))
|
|
|
|
return buf;
|
|
|
|
snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file);
|
1996-05-16 11:47:46 +00:00
|
|
|
if (file_readable(buf))
|
|
|
|
return buf;
|
1995-05-29 02:13:31 +00:00
|
|
|
return NULL;
|
1995-05-01 21:56:32 +00:00
|
|
|
}
|
1995-05-04 19:48:19 +00:00
|
|
|
|
|
|
|
void
|
1995-05-05 23:47:47 +00:00
|
|
|
systemChangeTerminal(char *color, const u_char c_term[],
|
|
|
|
char *mono, const u_char m_term[])
|
1995-05-04 19:48:19 +00:00
|
|
|
{
|
1995-05-19 16:58:58 +00:00
|
|
|
extern void init_acs(void);
|
|
|
|
|
1995-05-18 15:29:47 +00:00
|
|
|
if (OnVTY) {
|
1995-05-05 23:47:47 +00:00
|
|
|
if (ColorDisplay) {
|
|
|
|
setenv("TERM", color, 1);
|
|
|
|
setenv("TERMCAP", c_term, 1);
|
1995-05-18 15:29:47 +00:00
|
|
|
reset_shell_mode();
|
|
|
|
setterm(color);
|
|
|
|
init_acs();
|
|
|
|
cbreak(); noecho();
|
1995-05-05 23:47:47 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
setenv("TERM", mono, 1);
|
|
|
|
setenv("TERMCAP", m_term, 1);
|
1995-05-18 15:29:47 +00:00
|
|
|
reset_shell_mode();
|
|
|
|
setterm(mono);
|
|
|
|
init_acs();
|
|
|
|
cbreak(); noecho();
|
1995-05-05 23:47:47 +00:00
|
|
|
}
|
|
|
|
}
|
1995-06-11 19:33:05 +00:00
|
|
|
clear();
|
|
|
|
refresh();
|
|
|
|
dialog_clear();
|
1995-05-04 19:48:19 +00:00
|
|
|
}
|
|
|
|
|
1995-05-20 19:12:13 +00:00
|
|
|
int
|
|
|
|
vsystem(char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
1995-05-26 19:28:06 +00:00
|
|
|
int pstat;
|
1995-05-20 19:12:13 +00:00
|
|
|
pid_t pid;
|
|
|
|
int omask;
|
|
|
|
sig_t intsave, quitsave;
|
1995-12-07 10:34:59 +00:00
|
|
|
char *cmd;
|
|
|
|
int i;
|
1995-05-20 19:12:13 +00:00
|
|
|
|
1996-04-28 01:07:27 +00:00
|
|
|
cmd = (char *)alloca(FILENAME_MAX);
|
1995-05-20 19:12:13 +00:00
|
|
|
cmd[0] = '\0';
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(cmd, FILENAME_MAX, fmt, args);
|
|
|
|
va_end(args);
|
1995-05-29 11:01:42 +00:00
|
|
|
|
1995-05-20 19:12:13 +00:00
|
|
|
omask = sigblock(sigmask(SIGCHLD));
|
1996-04-28 20:54:11 +00:00
|
|
|
if (Fake) {
|
|
|
|
msgDebug("vsystem: Faked execution of `%s'\n", cmd);
|
|
|
|
return 0;
|
|
|
|
}
|
1995-05-29 11:01:42 +00:00
|
|
|
if (isDebug())
|
1995-12-07 10:34:59 +00:00
|
|
|
msgDebug("Executing command `%s'\n", cmd);
|
|
|
|
pid = fork();
|
|
|
|
if (pid == -1) {
|
1995-05-20 19:12:13 +00:00
|
|
|
(void)sigsetmask(omask);
|
|
|
|
i = 127;
|
1995-12-07 10:34:59 +00:00
|
|
|
}
|
|
|
|
else if (!pid) { /* Junior */
|
1995-05-20 19:12:13 +00:00
|
|
|
(void)sigsetmask(omask);
|
|
|
|
if (DebugFD != -1) {
|
|
|
|
dup2(DebugFD, 0);
|
|
|
|
dup2(DebugFD, 1);
|
|
|
|
dup2(DebugFD, 2);
|
|
|
|
}
|
1996-04-28 03:27:26 +00:00
|
|
|
else {
|
|
|
|
close(1); open("/dev/null", O_WRONLY);
|
|
|
|
dup2(1, 2);
|
|
|
|
}
|
|
|
|
if (!RunningAsInit)
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
|
|
|
|
else
|
|
|
|
execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL);
|
1995-12-07 10:34:59 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
intsave = signal(SIGINT, SIG_IGN);
|
|
|
|
quitsave = signal(SIGQUIT, SIG_IGN);
|
|
|
|
pid = waitpid(pid, &pstat, 0);
|
|
|
|
(void)sigsetmask(omask);
|
|
|
|
(void)signal(SIGINT, intsave);
|
|
|
|
(void)signal(SIGQUIT, quitsave);
|
|
|
|
i = (pid == -1) ? -1 : WEXITSTATUS(pstat);
|
|
|
|
if (isDebug())
|
|
|
|
msgDebug("Command `%s' returns status of %d\n", cmd, i);
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
systemCreateHoloshell(void)
|
|
|
|
{
|
1996-03-21 09:30:18 +00:00
|
|
|
if (OnVTY && RunningAsInit) {
|
1996-12-29 05:51:40 +00:00
|
|
|
|
|
|
|
if (ehs_pid != 0) {
|
|
|
|
int pstat;
|
|
|
|
|
|
|
|
if (kill(ehs_pid, 0) == 0) {
|
|
|
|
|
|
|
|
if (msgYesNo("There seems to be an emergency holographic shell\n"
|
|
|
|
"already running von VTY 4.\n"
|
|
|
|
"Kill it and start a new one?"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* try cleaning up as much as possible */
|
|
|
|
(void) kill(ehs_pid, SIGHUP);
|
|
|
|
sleep(1);
|
|
|
|
(void) kill(ehs_pid, SIGKILL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* avoid too many zombies */
|
|
|
|
(void) waitpid(ehs_pid, &pstat, WNOHANG);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ehs_pid = fork()) == 0) {
|
1995-12-07 10:34:59 +00:00
|
|
|
int i, fd;
|
|
|
|
struct termios foo;
|
|
|
|
extern int login_tty(int);
|
|
|
|
|
1996-12-11 19:35:26 +00:00
|
|
|
ioctl(0, TIOCNOTTY, NULL);
|
1996-12-12 08:23:51 +00:00
|
|
|
for (i = getdtablesize(); i >= 0; --i)
|
1995-12-07 10:34:59 +00:00
|
|
|
close(i);
|
1996-12-11 19:35:26 +00:00
|
|
|
fd = open("/dev/ttyv3", O_RDWR);
|
1995-12-07 10:34:59 +00:00
|
|
|
ioctl(0, TIOCSCTTY, &fd);
|
|
|
|
dup2(0, 1);
|
|
|
|
dup2(0, 2);
|
1996-12-11 19:35:26 +00:00
|
|
|
DebugFD = 2;
|
1995-12-07 10:34:59 +00:00
|
|
|
if (login_tty(fd) == -1)
|
|
|
|
msgDebug("Doctor: I can't set the controlling terminal.\n");
|
|
|
|
signal(SIGTTOU, SIG_IGN);
|
|
|
|
if (tcgetattr(fd, &foo) != -1) {
|
|
|
|
foo.c_cc[VERASE] = '\010';
|
|
|
|
if (tcsetattr(fd, TCSANOW, &foo) == -1)
|
|
|
|
msgDebug("Doctor: I'm unable to set the erase character.\n");
|
1995-05-29 11:01:42 +00:00
|
|
|
}
|
|
|
|
else
|
1995-12-07 10:34:59 +00:00
|
|
|
msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
|
|
|
|
execlp("sh", "-sh", 0);
|
|
|
|
msgDebug("Was unable to execute sh for Holographic shell!\n");
|
|
|
|
exit(1);
|
1995-05-18 09:02:06 +00:00
|
|
|
}
|
1996-04-29 21:15:44 +00:00
|
|
|
else {
|
1995-12-07 10:34:59 +00:00
|
|
|
msgNotify("Starting an emergency holographic shell on VTY4");
|
1996-05-01 03:31:08 +00:00
|
|
|
sleep(2);
|
1996-04-29 21:15:44 +00:00
|
|
|
}
|
1995-05-18 02:42:33 +00:00
|
|
|
}
|
1995-05-20 23:33:14 +00:00
|
|
|
}
|