-# $Id: Makefile.dist,v 1.1.1.1 1999/05/02 04:21:18 wsanchez Exp $
+# $Id: Makefile.dist,v 1.1 1999/05/02 04:21:18 wsanchez Exp $
PROG= at
SRCS= at.c panic.c parsetime.c
-# $Id: Makefile.dist,v 1.1.1.1 1999/05/02 04:21:19 wsanchez Exp $
+# $Id: Makefile.dist,v 1.1 1999/05/02 04:21:19 wsanchez Exp $
PROG= atrun
BINDIR= /usr/libexec
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $Id: atrun.8,v 1.1.1.1 1999/05/02 04:21:19 wsanchez Exp $
+.\" $Id: atrun.8,v 1.1 1999/05/02 04:21:19 wsanchez Exp $
.\"
.Dd December 5, 1993
.Dt ATRUN 8
.\" SUCH DAMAGE.
.\"
.\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93
-.\" $Id: getty.8,v 1.1.1.1 1999/05/02 04:21:29 wsanchez Exp $
+.\" $Id: getty.8,v 1.1 1999/05/02 04:21:29 wsanchez Exp $
.\"
.Dd June 4, 1993
.Dt GETTY 8
.\" SUCH DAMAGE.
.\"
.\" from: @(#)gettytab.5 8.4 (Berkeley) 4/19/94
-.\" $Id: gettytab.5,v 1.1.1.1 1999/05/02 04:21:29 wsanchez Exp $
+.\" $Id: gettytab.5,v 1.1 1999/05/02 04:21:29 wsanchez Exp $
.\"
.Dd April 19, 1994
.Dt GETTYTAB 5
.\" SUCH DAMAGE.
.\"
.\" from: @(#)ttys.5 8.1 (Berkeley) 6/4/93
-.\" $Id: ttys.5,v 1.1.1.1 1999/05/02 04:21:29 wsanchez Exp $
+.\" $Id: ttys.5,v 1.1 1999/05/02 04:21:29 wsanchez Exp $
.\"
.Dd June 4, 1993
.Dt TTYS 5
PROJECT_TYPE = Tool
CFILES = reboot.c
+DEFSFILES = kextmanager.defs
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist\
boot_hp300.8 boot_i386.8 boot_sparc.8 boot_tahoe.8\
- boot_vax.8 reboot.8
+ boot_vax.8 reboot.8 $(DEFSFILES)
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
+OTHER_OFILES = kextmanagerUser.o
+# OTHER_CFLAGS += -O0
--- /dev/null
+#include <IOKit/kext/kextmanager_mig.defs>
.Nd stopping and restarting the system
.Sh SYNOPSIS
.Nm halt
-.Op Fl lnq
+.Op Fl lnqu
.Nm
.Op Fl lnq
.Sh DESCRIPTION
.Fl n
option is not specified).
This option should probably not be used.
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
.El
.Pp
Normally, the
#include <string.h>
#include <unistd.h>
+#ifdef __APPLE__
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#include <mach/mach_port.h> // allocate
+#include <mach/mach.h> // task_self, etc
+#include <servers/bootstrap.h> // bootstrap
+#endif
+
void usage(void);
u_int get_pageins(void);
+#ifdef __APPLE__
+int reserve_reboot(void);
+#endif
int dohalt;
main(int argc, char *argv[])
{
struct passwd *pw;
- int ch, howto, i, fd, kflag, lflag, nflag, qflag, pflag, sverrno;
+ int ch, howto, i, fd, kflag, lflag, nflag, qflag, pflag, uflag, sverrno;
u_int pageins;
char *kernel, *p;
const char *user;
#ifndef __APPLE__
while ((ch = getopt(argc, argv, "dk:lnpq")) != -1)
#else
- while ((ch = getopt(argc, argv, "lnq")) != -1)
+ while ((ch = getopt(argc, argv, "lnqu")) != -1)
#endif
switch(ch) {
#ifndef __APPLE__
howto |= RB_POWEROFF;
break;
#endif
+ case 'u':
+ uflag = 1;
+ howto |= RB_UPSDELAY;
+ break;
case 'q':
qflag = 1;
break;
err(1, NULL);
}
+#ifdef __APPLE__
+ if (!lflag) { // shutdown(8) has already checked w/kextd
+ if ((errno = reserve_reboot()) && !qflag)
+ err(1, "couldn't lock for reboot");
+ }
+#endif
+
if (qflag) {
reboot(howto);
err(1, NULL);
pw->pw_name : "???";
if (dohalt) {
openlog("halt", 0, LOG_AUTH | LOG_CONS);
- syslog(LOG_CRIT, "halted by %s", user);
+ syslog(LOG_CRIT, "halted by %s%s", user,
+ (howto & RB_UPSDELAY) ? " with UPS delay":"");
} else {
openlog("reboot", 0, LOG_AUTH | LOG_CONS);
syslog(LOG_CRIT, "rebooted by %s", user);
reboot(howto);
/* FALLTHROUGH */
+#ifndef __APPLE__
restart:
+#endif
sverrno = errno;
errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
strerror(sverrno));
}
return pageins;
}
+
+#ifdef __APPLE__
+// XX another copy of this routine is in shutdown.c; it would be nice to share
+
+#define LCK_MAXTRIES 10
+#define LCK_DELAY 30
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot()
+{
+ int rval = ELAST+1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t tport, bsport, kxport, myport = MACH_PORT_NULL;
+ int busyStatus, nretries = LCK_MAXTRIES;
+ dev_path_t busyDev = "<unknown>";
+
+ // find kextd
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = task_get_bootstrap_port(tport, &bsport);
+ if (macherr) goto finish;
+ macherr = bootstrap_look_up(bsport, KEXTD_SERVER_NAME, &kxport);
+ if (macherr) goto finish;
+
+ // allocate a port to pass to kextd (in case we die)
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // loop trying to lock for reboot (i.e. no volumes are busy)
+ do {
+ nretries--;
+ macherr = kextmanager_lock_reboot(kxport, myport, busyDev, &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ if (*busyDev) {
+ warnx("%s is busy updating; delaying reboot (%d retries left)",
+ busyDev, nretries);
+ } else
+ warnx("kextd still starting up");
+ if (nretries) sleep(LCK_DELAY); // don't sleep the last time
+ }
+ } while (busyStatus == EBUSY && nretries > 0);
+
+ rval = busyStatus;
+
+finish:
+ if (macherr == BOOTSTRAP_UNKNOWN_SERVICE) {
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+ rval = 0;
+ } else if (macherr) {
+ warnx("couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = ELAST + 1;
+ }
+ if (rval && myport != MACH_PORT_NULL) {
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+ }
+
+ return rval;
+}
+#endif
HFILES = pathnames.h
CFILES = shutdown.c
+DEFSFILES = kextmanager.defs
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist\
- shutdown.8
+ shutdown.8 $(DEFSFILES)
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
+OTHER_OFILES = kextmanagerUser.o
+# OTHER_CFLAGS += -O0
--- /dev/null
+#include <IOKit/kext/kextmanager_mig.defs>
.Nm
.Op Fl
.Oo
-.Fl h |
+.Fl h
+.Op Fl u
+|
.Fl r | Fl k
.Oc
.Oo
does not actually halt the system, but leaves the
system multi-user with logins disabled (for all but super-user).
.It Fl o
-If one of the
-.Fl h ,
-.Fl p
+If
+.Fl h
or
.Fl r
is specified,
or
.Xr reboot 8 .
This option should probably not be used.
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
.It Ar time
.Ar Time
is the time at which
#include <bsm/libbsm.h>
#include <bsm/audit_uevents.h>
+#ifdef __APPLE__
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#include <mach/mach_port.h> // allocate
+#include <mach/mach.h> // task_self, etc
+#include <servers/bootstrap.h> // bootstrap
+#endif
#include "pathnames.h"
#undef S
static time_t offset, shuttime;
-static int dohalt, dopower, doreboot, killflg, mbuflen, oflag = 1;
+static int dohalt, dopower, doreboot, doups, killflg, mbuflen, oflag = 1;
static char mbuf[BUFSIZ];
static const char *nosync, *whom;
void timewarn(int);
void usage(const char *);
int audit_shutdown(int);
+#ifdef __APPLE__
+int reserve_reboot(void);
+#endif
int
main(argc, argv)
#ifndef __APPLE__
while ((ch = getopt(argc, argv, "-hknopr")) != -1)
#else
- while ((ch = getopt(argc, argv, "-hknor")) != -1)
+ while ((ch = getopt(argc, argv, "-hknoru")) != -1)
#endif
switch (ch) {
case '-':
break;
case 'k':
killflg = 1;
+ oflag = 0;
break;
case 'n':
nosync = "-n";
dopower = 1;
break;
#endif
+ case 'u':
+ doups = 1;
+ break;
case 'r':
doreboot = 1;
break;
if (oflag && !(dohalt || doreboot))
usage("-o requires -h or -r");
+
+ if (doups && !dohalt)
+ usage("-u requires -h");
#endif
if (nosync != NULL && !oflag)
{
char *empty_environ[] = { NULL };
- syslog(LOG_NOTICE, "%s by %s: %s",
+#ifdef __APPLE__
+ if ((errno = reserve_reboot()))
+ err(1, "couldn't lock for reboot");
+#endif
+
+ syslog(LOG_NOTICE, "%s%s by %s: %s",
#ifndef __APPLE__
doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
#else
doreboot ? "reboot" : dohalt ? "halt" :
#endif
- "shutdown", whom, mbuf);
+ "shutdown", doups?"with UPS delay":"", whom, mbuf);
#ifndef __APPLE__
(void)sleep(2);
#endif
warn(_PATH_REBOOT);
}
else if (dohalt) {
- execle(_PATH_HALT, "halt", "-l", nosync,
+ char *halt_args;
+ if(doups) {
+ halt_args = "-lu";
+ } else {
+ halt_args = "-l";
+ }
+ execle(_PATH_HALT, "halt", halt_args, nosync,
(char *)NULL, empty_environ);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
_PATH_HALT);
if (cp != NULL)
warnx("%s", cp);
(void)fprintf(stderr,
- "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]"
+ "usage: shutdown [-] [-h [-u] | -r | -k] [-o [-n]]"
" time [warning-message ...]\n");
exit(1);
}
}
return 1;
}
+
+
+#ifdef __APPLE__
+// XX copied from reboot.c; would be nice to share the code
+
+#define LCK_MAXTRIES 10
+#define LCK_DELAY 30
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot()
+{
+ int rval = ELAST+1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t tport, bsport, kxport, myport = MACH_PORT_NULL;
+ int busyStatus, nretries = LCK_MAXTRIES;
+ dev_path_t busyDev = "<unknown>";
+
+ // find kextd
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = task_get_bootstrap_port(tport, &bsport);
+ if (macherr) goto finish;
+ macherr = bootstrap_look_up(bsport, KEXTD_SERVER_NAME, &kxport);
+ if (macherr) goto finish;
+
+ // allocate a port to pass to kextd (in case we die)
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // loop trying to lock for reboot (i.e. no volumes are busy)
+ do {
+ nretries--;
+ macherr = kextmanager_lock_reboot(kxport, myport, busyDev, &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ if (*busyDev) {
+ warnx("%s is busy updating; delaying reboot (%d retries left)",
+ busyDev, nretries);
+ } else
+ warnx("kextd still starting up");
+ if (nretries) sleep(LCK_DELAY); // don't sleep the last time
+ }
+ } while (busyStatus == EBUSY && nretries > 0);
+
+ rval = busyStatus;
+
+finish:
+ if (macherr == BOOTSTRAP_UNKNOWN_SERVICE) {
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+ rval = 0;
+ } else if (macherr) {
+ warnx("couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = ELAST + 1;
+ }
+ if (rval && myport != MACH_PORT_NULL) {
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+ }
+
+ return rval;
+}
+#endif
+