PROJECTVERSION = 2.8
PROJECT_TYPE = Aggregate
-SUBPROJECTS =
-
TOOLS = dynamic_pager.tproj ac.tproj accton.tproj arch.tproj at.tproj\
atrun.tproj chkpasswd.tproj chpass.tproj dmesg.tproj\
getty.tproj halt.tproj hostinfo.tproj init.tproj iostat.tproj\
- kgmon.tproj kmodload.tproj kmodstat.tproj kmodunload.tproj\
- ktrace.tproj login.tproj mach_init.tproj makekey.tproj\
- mkfile.tproj nvram.tproj passwd.tproj pwd_mkdb.tproj\
- reboot.tproj shutdown.tproj sync.tproj sysctl.tproj\
- update.tproj vipw.tproj zic.tproj zdump.tproj vm_stat.tproj\
- zprint.tproj top.tproj kextload.tproj kextunload.tproj kextd.tproj\
- latency.tproj sc_usage.tproj fs_usage.tproj
+ kgmon.tproj ktrace.tproj login.tproj mach_init.tproj\
+ makekey.tproj mkfile.tproj nvram.tproj passwd.tproj\
+ pwd_mkdb.tproj reboot.tproj shutdown.tproj sync.tproj\
+ sysctl.tproj update.tproj vipw.tproj zic.tproj zdump.tproj\
+ vm_stat.tproj zprint.tproj top.tproj latency.tproj\
+ sc_usage.tproj fs_usage.tproj kdump.tproj
LIBRARIES = dp_notify_lib
{
- English_RESOURCES = {};
+ "English_RESOURCES" = {};
FILESTABLE = {
- CLASSES = (zprint.c);
- C_FILES = ();
+ CLASSES = ("zprint.c");
+ "C_FILES" = ();
FRAMEWORKS = ();
HEADERSEARCH = ();
- H_FILES = ();
- M_FILES = ();
- OTHER_LINKED = ();
- OTHER_SOURCES = (Makefile.preamble, Makefile, README.rtf, APPLE_LICENSE);
- PRECOMPILED_HEADERS = ();
- PROJECT_HEADERS = ();
- PUBLIC_HEADERS = ();
+ "H_FILES" = ();
+ "M_FILES" = ();
+ "OTHER_LINKED" = ();
+ "OTHER_SOURCES" = ("Makefile.preamble", Makefile, "README.rtf", "APPLE_LICENSE");
+ "PRECOMPILED_HEADERS" = ();
+ "PROJECT_HEADERS" = ();
+ "PUBLIC_HEADERS" = ();
SUBPROJECTS = (
- dynamic_pager.tproj,
- dp_notify_lib,
- ac.tproj,
- accton.tproj,
- arch.tproj,
- at.tproj,
- atrun.tproj,
- chkpasswd.tproj,
- chpass.tproj,
- dmesg.tproj,
- fastboot.tproj,
- getty.tproj,
- halt.tproj,
- hostinfo.tproj,
- init.tproj,
- iostat.tproj,
- kgmon.tproj,
- kmodload.tproj,
- kmodstat.tproj,
- kmodunload.tproj,
- ktrace.tproj,
- login.tproj,
- mach_init.tproj,
- makekey.tproj,
- mkfile.tproj,
- nologin.tproj,
- nvram.tproj,
- pagesize.tproj,
- passwd.tproj,
- pwd_mkdb.tproj,
- reboot.tproj,
- shutdown.tproj,
- sync.tproj,
- sysctl.tproj,
- update.tproj,
- vipw.tproj,
- zic.tproj,
- zdump.tproj,
- vm_stat.tproj,
- zprint.tproj,
- top.tproj,
- kextload.tproj,
- kextunload.tproj,
- kextd.tproj,
- latency.tproj,
- sc_usage.tproj,
- fs_usage.tproj
+ "dynamic_pager.tproj",
+ "dp_notify_lib",
+ "ac.tproj",
+ "accton.tproj",
+ "arch.tproj",
+ "at.tproj",
+ "atrun.tproj",
+ "chkpasswd.tproj",
+ "chpass.tproj",
+ "dmesg.tproj",
+ "fastboot.tproj",
+ "getty.tproj",
+ "halt.tproj",
+ "hostinfo.tproj",
+ "init.tproj",
+ "iostat.tproj",
+ "kgmon.tproj",
+ "ktrace.tproj",
+ "login.tproj",
+ "mach_init.tproj",
+ "makekey.tproj",
+ "mkfile.tproj",
+ "nologin.tproj",
+ "nvram.tproj",
+ "pagesize.tproj",
+ "passwd.tproj",
+ "pwd_mkdb.tproj",
+ "reboot.tproj",
+ "shutdown.tproj",
+ "sync.tproj",
+ "sysctl.tproj",
+ "update.tproj",
+ "vipw.tproj",
+ "zic.tproj",
+ "zdump.tproj",
+ "vm_stat.tproj",
+ "zprint.tproj",
+ "top.tproj",
+ "latency.tproj",
+ "sc_usage.tproj",
+ "fs_usage.tproj",
+ "kdump.tproj"
);
};
LANGUAGE = English;
- LOCALIZABLE_FILES = {};
+ "LOCALIZABLE_FILES" = {};
MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = system_cmds;
+ "NEXTSTEP_BUILDTOOL" = "/bin/gnumake";
+ "NEXTSTEP_JAVA_COMPILER" = "/usr/bin/javac";
+ "NEXTSTEP_OBJCPLUS_COMPILER" = "/usr/bin/cc";
+ "PDO_UNIX_JAVA_COMPILER" = "$(NEXTDEV_BIN)/javac";
+ "PDO_UNIX_OBJCPLUS_COMPILER" = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = "system_cmds";
PROJECTTYPE = Aggregate;
- PROJECTVERSION = 2.8;
+ PROJECTVERSION = "2.8";
TARGETS = ();
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+ "WINDOWS_JAVA_COMPILER" = "$(JDKBINDIR)/javac.exe";
+ "WINDOWS_OBJCPLUS_COMPILER" = "$(DEVDIR)/gcc";
}
-{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
-\paperw4880
-\paperh7420
-\margl120
-\margr120
-\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b\i0\ulnone\fs24\fc0\cf0 system_cmds failures\
+{\rtf1\mac\ansicpg10000\cocoartf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;\f2\fswiss\fcharset77 Helvetica-Oblique;
+}
+{\colortbl;\red255\green255\blue255;}
+\margl120\margr120\vieww4640\viewh7420\viewkind0
+\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\ql\qnatural
+
+\f0\b\fs24 \cf0 system_cmds failures\
-\b0 \
+\f1\b0 \
cgore\
<a.out.h>\
\
KERNBASE undeclared\
\
mach_swapon\
- <bsd/sys/table.h> not found\
+ <sys/table.h> not found\
\
savecore\
KERNBASE undeclared\
\
vmstat\
-\i <vm/vm.h> not found\
-
-}
+\f2\i <vm/vm.h> not found\
+}
\ No newline at end of file
# Makefile API), which are rules that get invoked before and after the install
# target runs. Such rules should be specified with the '::' syntax rather than
# a single colon.
+
+after_install:
+ mkdir -p "$(DSTROOT)/usr/share/man/man8"
+ install -c -m 644 ac.8 "$(DSTROOT)/usr/share/man/man8/ac.8"
# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
OTHER_GENERATED_OFILES = $(VERS_OFILE)
+AFTER_INSTALL = after_install
CFILES = arch.c
-OTHERSRCS = Makefile PB.project Makefile.postamble
+OTHERSRCS = Makefile PB.project Makefile.postamble arch.1 machine.1
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
after_install::
+ install -d $(DSTROOT)/usr/share/man/man1
+ install -c -m 444 arch.1 $(DSTROOT)/usr/share/man/man1
+ install -c -m 444 machine.1 $(DSTROOT)/usr/share/man/man1
@-$(RM) -f $(DSTROOT)$(INSTALLDIR)/machine
- ln $(DSTROOT)$(INSTALLDIR)/arch $(DSTROOT)$(INSTALLDIR)/machine
\ No newline at end of file
+ ln $(DSTROOT)$(INSTALLDIR)/arch $(DSTROOT)$(INSTALLDIR)/machine
--- /dev/null
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by SigmaSoft, Th. Lockert.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: arch.1,v 1.2 1996/06/29 20:29:34 tholo Exp $
+.\"
+.\" Modifications made 8/20/97 (c) Apple Computer, Inc.
+
+.Dd August 20, 1997
+.Dt ARCH 1
+.Os Mac OS X
+.Sh NAME
+.Nm arch
+.Nd print architecture type
+.Sh SYNOPSIS
+.Nm arch
+.Sh DESCRIPTION
+The
+.Nm arch
+command displays the machine's architecture type.
+.Sh SEE ALSO
+.Xr machine 1
--- /dev/null
+.\" $OpenBSD: machine.1,v 1.2 1996/06/26 05:36:23 deraadt Exp $
+.\" Copyright (c) 1980, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)machine.1 5.5 (Berkeley) 7/26/91
+.\"
+.Dd July 26, 1991
+.Dt MACHINE 1
+.Os
+.Sh NAME
+.Nm machine
+.Nd print machine type
+.Sh SYNOPSIS
+.Nm machine
+.Sh DESCRIPTION
+The
+.Nm machine
+command displays the machine type.
+.Sh SEE ALSO
+.Xr make 1
+.Sh HISTORY
+The
+.Nm machine
+command is
+.Ud .
$(LN) -f $(INSTALLED_PRODUCTS) $(DSTROOT)$(INSTALLDIR)/atq
$(LN) -f $(INSTALLED_PRODUCTS) $(DSTROOT)$(INSTALLDIR)/atrm
$(LN) -f $(INSTALLED_PRODUCTS) $(DSTROOT)$(INSTALLDIR)/batch
+ mkdir -p "$(DSTROOT)/private/var/at/spool"
+ touch "$(DSTROOT)/private/var/at/at.deny"
+ mkdir -p "$(DSTROOT)/usr/share/man/man1"
+ install -c -m 644 at.1 "$(DSTROOT)/usr/share/man/man1/at.1"
+ ln -f "$(DSTROOT)/usr/share/man/man1/at.1" "$(DSTROOT)/usr/share/man/man1/atrm.1"
+ ln -f "$(DSTROOT)/usr/share/man/man1/at.1" "$(DSTROOT)/usr/share/man/man1/atq.1"
+ ln -f "$(DSTROOT)/usr/share/man/man1/at.1" "$(DSTROOT)/usr/share/man/man1/batch.1"
NEXTSTEP_INSTALLDIR = /usr/bin
WINDOWS_INSTALLDIR = /Library/Executables
PDO_UNIX_INSTALLDIR = /bin
-LIBS =
+LIBS = -lcurses
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
.\"
-.Dd March 28, 2000
+.Dd November 26, 2001
.Dt FS_USAGE 1
.Os "Mac OS X"
.Sh NAME
this includes all system processes except the running
fs_usage process,
Terminal, telnetd, sshd, rlogind, tcsh, csh and sh.
-These defaluts can be overridden such that output is limited to
+These defaults can be overridden such that output is limited to
include or exclude a list of processes specified by the user.
.Pp
The output presented by
relating to the given list of process ids or commands.
.El
.Pp
-If "/tmp/FileTracing" is present when a Carbon Application
-is launched, then the high level Carbon FileManager
+If you set the DYLD_IMAGE_SUFFIX environment variable
+to "_debug", then an application will use
+the debug version of all libraries including the
+Carbon FileManager. See dyld(1). When
+fs_usage is run against a Carbon Application launched
+in this environment, then the high level Carbon FileManager
calls will be displayed bracketing the system calls that they
are built on.
.Pp
.Pp
.It TIMESTAMP
TOD when call occurred. Wide mode will
-have millesecond granularity.
+have millisecond granularity.
.It CALL
-the name of the filesystem call or page-in.
+the name of the filesystem call, page-in, page-out or physical disk access.
.It FILE DESCRIPTOR
Of the form F=x, x is a file descriptor. Depending
on the type of system call, this will be either
.It FAULT ADDRESS
Of the form A=0xnnnnnnnn, where 0xnnnnnnnn is the
address being faulted.
+.It DISK BLOCK NUMBER
+Of the form D=0xnnnnnnnn, where 0xnnnnnnnn is the block number
+of the physical disk block being read or written.
.It TIME INTERVAL(W)
The elapsed time spent in the system call.
A 'W' after the elapsed time indicates
.Xr top 1
.Xr sc_usage 1
.Xr latency 1
+.Xr dyld 1
#include <nlist.h>
#include <fcntl.h>
#include <string.h>
+#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <libc.h>
#include <termios.h>
-#include <bsd/curses.h>
#include <sys/ioctl.h>
#ifndef KERNEL_PRIVATE
extern int errno;
+
+
+#define MAXINDEX 2048
+
+typedef struct LibraryInfo {
+ unsigned long address;
+ char *name;
+} LibraryInfo;
+
+LibraryInfo frameworkInfo[MAXINDEX];
+int numFrameworks = 0;
+
+char seg_addr_table[256]="/AppleInternal/Developer/seg_addr_table";
+
+char *lookup_name();
+
+
/*
MAXCOLS controls when extra data kicks in.
MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
int need_new_map = 1;
int bias_secs;
int wideflag = 0;
+int columns = 0;
int select_pid_mode = 0; /* Flag set indicates that output is restricted
to selected pids or commands */
int one_good_pid = 0; /* Used to fail gracefully when bad pids given */
+#define NFS_DEV -1
+
+struct diskrec {
+ struct diskrec *next;
+ char *diskname;
+ int dev;
+};
+
+struct diskio {
+ struct diskio *next;
+ struct diskio *prev;
+ int type;
+ int bp;
+ int dev;
+ int blkno;
+ int iosize;
+ int io_errno;
+ int issuing_thread;
+ int completion_thread;
+ char issuing_command[MAXCOMLEN];
+ double issued_time;
+ double completed_time;
+};
+
+struct diskrec *disk_list = NULL;
+struct diskio *free_diskios = NULL;
+struct diskio *busy_diskios = NULL;
+
+struct diskio *insert_diskio();
+struct diskio *complete_diskio();
+void free_diskio();
+void print_diskio();
+void format_print();
+char *find_disk_name();
+
+
#define DBG_ZERO_FILL_FAULT 1
#define DBG_PAGEIN_FAULT 2
#define DBG_COW_FAULT 3
#define TRACE_STRING_EXEC 0x07010008
#define MACH_vmfault 0x01300000
+#define MACH_pageout 0x01300004
#define MACH_sched 0x01400000
#define MACH_stkhandoff 0x01400008
#define VFS_LOOKUP 0x03010090
#define BSC_exit 0x040C0004
+#define P_WrData 0x03020000
+#define P_RdData 0x03020008
+#define P_WrMeta 0x03020020
+#define P_RdMeta 0x03020028
+#define P_PgOut 0x03020040
+#define P_PgIn 0x03020048
+#define P_WrDataAsync 0x03020010
+#define P_RdDataAsync 0x03020018
+#define P_WrMetaAsync 0x03020030
+#define P_RdMetaAsync 0x03020038
+#define P_PgOutAsync 0x03020050
+#define P_PgInAsync 0x03020058
+
+#define P_WrDataDone 0x03020004
+#define P_RdDataDone 0x0302000C
+#define P_WrMetaDone 0x03020024
+#define P_RdMetaDone 0x0302002C
+#define P_PgOutDone 0x03020044
+#define P_PgInDone 0x0302004C
+#define P_WrDataAsyncDone 0x03020014
+#define P_RdDataAsyncDone 0x0302001C
+#define P_WrMetaAsyncDone 0x03020034
+#define P_RdMetaAsyncDone 0x0302003C
+#define P_PgOutAsyncDone 0x03020054
+#define P_PgInAsyncDone 0x0302005C
+
+
#define MSC_map_fd 0x010c00ac
#define BSC_recvmsg 0x040C006C
#define BSC_sendmsg 0x040C0070
#define BSC_close 0x040C0018
#define BSC_link 0x040C0024
#define BSC_unlink 0x040C0028
+#define BSC_chdir 0x040c0030
+#define BSC_fchdir 0x040c0034
#define BSC_mknod 0x040C0038
#define BSC_chmod 0x040C003C
#define BSC_chown 0x040C0040
#define BSC_access 0x040C0084
#define BSC_chflags 0x040C0088
#define BSC_fchflags 0x040C008C
-#define BSC_sync 0x040C0090
+#define BSC_sync 0x040C0090
+#define BSC_revoke 0x040C00E0
#define BSC_symlink 0x040C00E4
-#define BSC_readlink 0x040C00E8
+#define BSC_readlink 0x040C00E8
+#define BSC_chroot 0x040C00F4
#define BSC_fsync 0x040C017C
#define BSC_readv 0x040C01E0
#define BSC_writev 0x040C01E4
#define BSC_fchown 0x040C01EC
#define BSC_fchmod 0x040C01F0
-#define BSC_rename 0x040C0200
+#define BSC_rename 0x040C0200
+#define BSC_mkfifo 0x040c0210
#define BSC_mkdir 0x040C0220
-#define BSC_rmdir 0x040C0224
+#define BSC_rmdir 0x040C0224
+#define BSC_utimes 0x040C0228
+#define BSC_futimes 0x040C022C
#define BSC_statfs 0x040C0274
#define BSC_fstatfs 0x040C0278
#define BSC_stat 0x040C02F0
#define BSC_mmap 0x040c0314
#define BSC_lseek 0x040c031c
#define BSC_truncate 0x040C0320
-#define BSC_ftruncate 0x040C0324
+#define BSC_ftruncate 0x040C0324
+#define BSC_undelete 0x040C0334
#define BSC_statv 0x040C0364
#define BSC_lstatv 0x040C0368
#define BSC_fstatv 0x040C036C
-#define BSC_mkcomplex 0x040C0360
+#define BSC_mkcomplex 0x040C0360
#define BSC_getattrlist 0x040C0370
#define BSC_setattrlist 0x040C0374
#define BSC_getdirentriesattr 0x040C0378
#define BSC_exchangedata 0x040C037C
#define BSC_checkuseraccess 0x040C0380
-#define BSC_searchfs 0x040C0384
+#define BSC_searchfs 0x040C0384
+#define BSC_delete 0x040C0388
+#define BSC_copyfile 0x040C038C
+#define BSC_fsctl 0x040C03C8
+#define BSC_load_shared_file 0x040C04A0
// Carbon File Manager support
#define FILEMGR_PBGETCATALOGINFO 0x1e000020
#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
#define DBG_FUNC_MASK 0xfffffffc
-/* Default divisor */
-#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
-double divisor = DIVISOR;
+double divisor = 0.0; /* Trace divisor converts to microseconds */
int mib[6];
size_t needed;
}
+void get_screenwidth()
+{
+ struct winsize size;
+
+ columns = MAXCOLS;
+
+ if (isatty(1)) {
+ if (ioctl(1, TIOCGWINSZ, &size) != -1)
+ columns = size.ws_col;
+ }
+}
+
+
void sigwinch()
{
- if (!wideflag)
- initscr();
+ if (!wideflag)
+ get_screenwidth();
}
int
printf("'fs_usage' must be run as root...\n");
exit(1);
}
-
- initscr();
+ get_screenwidth();
/* get our name */
if (argc > 0) {
break;
case 'w':
wideflag = 1;
- if (COLS < MAX_WIDE_MODE_COLS)
- COLS = MAX_WIDE_MODE_COLS;
+ if (columns < MAX_WIDE_MODE_COLS)
+ columns = MAX_WIDE_MODE_COLS;
break;
default:
exit_usage(myname);
{
argtopid("Terminal");
argtopid("telnetd");
+ argtopid("telnet");
argtopid("sshd");
argtopid("rlogind");
argtopid("tcsh");
/* set up signal handlers */
signal(SIGINT, leave);
signal(SIGQUIT, leave);
+ signal(SIGHUP, leave);
signal(SIGTERM, leave);
signal(SIGWINCH, sigwinch);
if ((my_buffer = malloc(SAMPLE_SIZE * sizeof(kd_buf))) == (char *)0)
quit("can't allocate memory for tracing info\n");
+ ReadSegAddrTable();
+ cache_disk_names();
+
set_remove();
set_numbufs(SAMPLE_SIZE);
set_init();
/* main loop */
while (1) {
- usleep(1000 * 50);
+ usleep(1000 * 25);
sample_sc();
}
void
find_proc_names()
{
- size_t bufSize = 0;
+ size_t bufSize = 0;
struct kinfo_proc *kp;
int quit();
return ((struct th_info *)0);
}
+
+mark_thread_waited(int thread) {
+ struct th_info *ti;
+
+ for (ti = th_state; ti < &th_state[cur_max]; ti++) {
+ if (ti->thread == thread) {
+ ti->waited = 1;
+ }
+ }
+}
+
+
void
set_enable(int val)
{
void
set_remove()
{
- extern int errno;
-
errno = 0;
mib[0] = CTL_KERN;
long *sargptr;
unsigned long long now;
struct th_info *ti;
+ struct diskio *dio;
void enter_syscall();
void exit_syscall();
void kill_thread_map();
thread = kd[i].arg5 & KDBG_THREAD_MASK;
debugid = kd[i].debugid;
type = kd[i].debugid & DBG_FUNC_MASK;
+
+ now = (((unsigned long long)kd[i].timestamp.tv_sec) << 32) |
+ (unsigned long long)((unsigned int)(kd[i].timestamp.tv_nsec));
+
switch (type) {
+ case P_RdMeta:
+ case P_WrMeta:
+ case P_RdData:
+ case P_WrData:
+ case P_PgIn:
+ case P_PgOut:
+ case P_RdMetaAsync:
+ case P_WrMetaAsync:
+ case P_RdDataAsync:
+ case P_WrDataAsync:
+ case P_PgInAsync:
+ case P_PgOutAsync:
+ insert_diskio(type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4, thread, (double)now);
+ continue;
+
+ case P_RdMetaDone:
+ case P_WrMetaDone:
+ case P_RdDataDone:
+ case P_WrDataDone:
+ case P_PgInDone:
+ case P_PgOutDone:
+ case P_RdMetaAsyncDone:
+ case P_WrMetaAsyncDone:
+ case P_RdDataAsyncDone:
+ case P_WrDataAsyncDone:
+ case P_PgInAsyncDone:
+ case P_PgOutAsyncDone:
+ if (dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now)) {
+ print_diskio(dio);
+ free_diskio(dio);
+ }
+ continue;
+
+
case TRACE_DATA_NEWTHREAD:
for (n = 0, ti = th_state; ti < &th_state[MAX_THREADS]; ti++, n++) {
case MACH_sched:
case MACH_stkhandoff:
- if (ti = find_thread(thread, 0))
- ti->waited = 1;
+ mark_thread_waited(thread);
continue;
case VFS_LOOKUP:
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
ti->pathptr = sargptr;
-
} else {
sargptr = ti->pathptr;
if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
continue;
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (debugid & DBG_FUNC_START)
+ {
+ (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
+ continue;
+ }
+
*sargptr++ = kd[i].arg1;
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
}
continue;
}
- now = (((unsigned long long)kd[i].timestamp.tv_sec) << 32) |
- (unsigned long long)((unsigned int)(kd[i].timestamp.tv_nsec));
if (debugid & DBG_FUNC_START) {
char *p;
}
switch (type) {
+ case MACH_pageout:
+ if (kd[i].arg2)
+ exit_syscall("PAGE_OUT_D", thread, type, 0, kd[i].arg1, 0, 4, (double)now);
+ else
+ exit_syscall("PAGE_OUT_V", thread, type, 0, kd[i].arg1, 0, 4, (double)now);
+ break;
+
case MACH_vmfault:
if (kd[i].arg2 == DBG_PAGEIN_FAULT)
- exit_syscall("PAGE_IN", thread, type, 0, kd[i].arg1, 0, 2, (double)now);
+ exit_syscall("PAGE_IN", thread, type, kd[i].arg4, kd[i].arg1, 0, 6, (double)now);
+ else if (kd[i].arg2 == DBG_CACHE_HIT_FAULT)
+ exit_syscall("CACHE_HIT", thread, type, 0, kd[i].arg1, 0, 2, (double)now);
else {
if (ti = find_thread(thread, type)) {
if (ti == &th_state[cur_max - 1])
case BSC_stat:
exit_syscall("stat", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
break;
+
+ case BSC_load_shared_file:
+ exit_syscall("load_sf", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
case BSC_open:
exit_syscall("open", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
exit_syscall("access", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
break;
+ case BSC_chdir:
+ exit_syscall("chdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_chroot:
+ exit_syscall("chroot", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_utimes:
+ exit_syscall("utimes", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_delete:
+ exit_syscall("delete", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_undelete:
+ exit_syscall("undelete", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_revoke:
+ exit_syscall("revoke", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_fsctl:
+ exit_syscall("fsctl", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
case BSC_chflags:
exit_syscall("chflags", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
break;
-
+
case BSC_fchflags:
exit_syscall("fchflags", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
break;
+
+ case BSC_fchdir:
+ exit_syscall("fchdir", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
+ break;
+
+ case BSC_futimes:
+ exit_syscall("futimes", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
+ break;
case BSC_sync:
exit_syscall("sync", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
exit_syscall("fchmod", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
break;
- case BSC_rename:
- exit_syscall("rename", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
- break;
-
case BSC_mkdir:
exit_syscall("mkdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
break;
+
+ case BSC_mkfifo:
+ exit_syscall("mkfifo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
case BSC_rmdir:
exit_syscall("rmdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
exit_syscall("getdirentriesattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 1, (double)now);
break;
+
case BSC_exchangedata:
exit_syscall("exchangedata", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
break;
+
+ case BSC_rename:
+ exit_syscall("rename", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
+ case BSC_copyfile:
+ exit_syscall("copyfile", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
+ break;
+
case BSC_checkuseraccess:
exit_syscall("checkuseraccess", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
switch (type) {
+ case MACH_pageout:
case MACH_vmfault:
case MSC_map_fd:
case BSC_mmap:
case BSC_recvfrom:
case BSC_sendto:
case BSC_stat:
+ case BSC_load_shared_file:
case BSC_open:
case BSC_close:
case BSC_read:
case BSC_access:
case BSC_chflags:
case BSC_fchflags:
+ case BSC_fchdir:
+ case BSC_futimes:
+ case BSC_chdir:
+ case BSC_utimes:
+ case BSC_chroot:
+ case BSC_undelete:
+ case BSC_delete:
+ case BSC_revoke:
+ case BSC_fsctl:
+ case BSC_copyfile:
case BSC_sync:
case BSC_symlink:
case BSC_readlink:
case BSC_fchmod:
case BSC_rename:
case BSC_mkdir:
+ case BSC_mkfifo:
case BSC_rmdir:
case BSC_statfs:
case BSC_fstatfs:
return;
if (i >= cur_max)
cur_max = i + 1;
+
if ((type >> 24) == FILEMGR_CLASS) {
ti->in_filemgr = 1;
sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
tsclen = strlen(buf);
- if (COLS > MAXCOLS || wideflag) {
+ if (columns > MAXCOLS || wideflag) {
usecs = l_usecs - (long long)((long long)secs * 1000000);
sprintf(&buf[tsclen], ".%03ld", (long)usecs / 1000);
tsclen = strlen(buf);
/*
Calculate white space out to command
*/
- if (COLS > MAXCOLS || wideflag)
+ if (columns > MAXCOLS || wideflag)
{
- clen = COLS - (tsclen + nmclen + argsclen + 20);
+ clen = columns - (tsclen + nmclen + argsclen + 20);
}
else
- clen = COLS - (tsclen + nmclen + argsclen + 12);
+ clen = columns - (tsclen + nmclen + argsclen + 12);
if(clen > 0)
{
printf(buf);
}
- if (COLS > MAXCOLS || wideflag)
+ if (columns > MAXCOLS || wideflag)
printf("%-20.20s\n", map->command);
else
printf("%-12.12s\n", map->command);
ti->arg4 = kd->arg4;
ti->pathptr = (long *)0;
ti->pathname[0] = 0;
-
break;
default:
exit_syscall(char *sc_name, int thread, int type, int error, int retval,
int has_fd, int has_ret, double now)
{
- struct th_info *ti;
+ struct th_info *ti;
+
+ if ((ti = find_thread(thread, type)) == (struct th_info *)0)
+ return;
+
+ format_print(ti, sc_name, thread, type, error, retval, has_fd, has_ret, now, ti->stime, ti->waited, ti->pathname, NULL);
+
+ if (ti == &th_state[cur_max - 1])
+ cur_max--;
+ ti->thread = 0;
+}
+
+
+
+void
+format_print(struct th_info *ti, char *sc_name, int thread, int type, int error, int retval,
+ int has_fd, int has_ret, double now, double stime, int waited, char *pathname, struct diskio *dio)
+{
int secs;
int usecs;
int nopadding;
long long l_usecs;
long curr_time;
+ char *command_name;
kd_threadmap *map;
kd_threadmap *find_thread_map();
int len = 0;
int clen = 0;
+ char *framework_name;
char buf[MAXCOLS];
- if ((ti = find_thread(thread, type)) == (struct th_info *)0)
- return;
- map = find_thread_map(thread);
+ command_name = "";
+
+ if (dio)
+ command_name = dio->issuing_command;
+ else {
+ if (map = find_thread_map(thread))
+ command_name = map->command;
+ }
l_usecs = (long long)(now / divisor);
secs = l_usecs / 1000000;
sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
clen = strlen(buf);
- if (COLS > MAXCOLS || wideflag) {
+ if (columns > MAXCOLS || wideflag) {
nopadding = 0;
usecs = l_usecs - (long long)((long long)secs * 1000000);
sprintf(&buf[clen], ".%03ld", (long)usecs / 1000);
clen = strlen(buf);
+
if ((type >> 24) != FILEMGR_CLASS) {
if (find_thread(thread, -1)) {
sprintf(&buf[clen], " ");
} else
nopadding = 1;
- if (((type >> 24) == FILEMGR_CLASS) && (COLS > MAXCOLS || wideflag))
+ if (((type >> 24) == FILEMGR_CLASS) && (columns > MAXCOLS || wideflag))
sprintf(&buf[clen], " %-18.18s", sc_name);
else
sprintf(&buf[clen], " %-15.15s", sc_name);
clen = strlen(buf);
-
- if (COLS > MAXCOLS || wideflag) {
+
+ framework_name = (char *)0;
+
+ if (columns > MAXCOLS || wideflag) {
+ if (has_ret == 7) {
+ sprintf(&buf[clen], " D=0x%8.8x", dio->blkno);
+
+ clen = strlen(buf);
+
+ if (dio->io_errno)
+ sprintf(&buf[clen], " [%3d] ", dio->io_errno);
+ else
+ sprintf(&buf[clen], " B=0x%-6x /dev/%s", dio->iosize, find_disk_name(dio->dev));
+ } else {
+
if (has_fd == 2 && error == 0)
sprintf(&buf[clen], " F=%-3d", retval);
else if (has_fd == 1)
sprintf(&buf[clen], " F=%-3d", ti->arg1);
- else if (has_ret != 2)
+ else if (has_ret != 2 && has_ret != 6)
sprintf(&buf[clen], " ");
clen = strlen(buf);
- if (error)
+ if (has_ret == 2 || has_ret == 6)
+ framework_name = lookup_name(retval);
+
+ if (error && has_ret != 6)
sprintf(&buf[clen], "[%3d] ", error);
else if (has_ret == 3)
sprintf(&buf[clen], "O=0x%8.8x", ti->arg3);
else if (has_ret == 5)
sprintf(&buf[clen], "O=0x%8.8x", retval);
else if (has_ret == 2)
- sprintf(&buf[clen], " A=0x%8.8x ", retval);
+ sprintf(&buf[clen], " A=0x%8.8x ", retval);
+ else if (has_ret == 6)
+ sprintf(&buf[clen], " A=0x%8.8x B=0x%-8x", retval, error);
else if (has_ret == 1)
sprintf(&buf[clen], " B=0x%-6x", retval);
else if (has_ret == 4)
- sprintf(&buf[clen], "R=0x%-8x", retval);
+ sprintf(&buf[clen], "B=0x%-8x", retval);
else
sprintf(&buf[clen], " ");
- clen = strlen(buf);
+ }
+ clen = strlen(buf);
}
printf(buf);
/*
Calculate space available to print pathname
*/
- if (COLS > MAXCOLS || wideflag)
- clen = COLS - (clen + 13 + 20);
+ if (columns > MAXCOLS || wideflag)
+ clen = columns - (clen + 13 + 20);
else
- clen = COLS - (clen + 13 + 12);
+ clen = columns - (clen + 13 + 12);
if ((type >> 24) != FILEMGR_CLASS && !nopadding)
clen -= 3;
- sprintf(&buf[0], " %s ", ti->pathname);
+ if (framework_name)
+ sprintf(&buf[0], " %s ", framework_name);
+ else
+ sprintf(&buf[0], " %s ", pathname);
len = strlen(buf);
if (clen > len)
printf(&buf[len - clen]);
}
- usecs = (unsigned long)(((double)now - ti->stime) / divisor);
+ usecs = (unsigned long)((now - stime) / divisor);
secs = usecs / 1000000;
usecs -= secs * 1000000;
if ((type >> 24) != FILEMGR_CLASS && !nopadding)
printf(" ");
- printf(" %2ld.%06ld", (long)secs, (long)usecs);
- if (ti->waited)
+ printf(" %2ld.%06ld", (unsigned long)secs, (unsigned long)usecs);
+
+ if (waited)
printf(" W");
else
printf(" ");
- if (map) {
- if (COLS > MAXCOLS || wideflag)
- printf(" %-20.20s", map->command);
- else
- printf(" %-12.12s", map->command);
- }
- printf("\n");
+ if (columns > MAXCOLS || wideflag)
+ printf(" %-20.20s", command_name);
+ else
+ printf(" %-12.12s", command_name);
- if (ti == &th_state[cur_max - 1])
- cur_max--;
- ti->thread = 0;
+ printf("\n");
fflush (0);
}
unsigned int proc_to_abs_num;
unsigned int proc_to_abs_denom;
- extern void MKGetTimeBaseInfo(unsigned int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
+ extern void MKGetTimeBaseInfo(unsigned int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
&proc_to_abs_num, &proc_to_abs_denom);
if (mapptr = (kd_threadmap *) malloc(size))
bzero (mapptr, size);
else
- {
- printf("Thread map is not initialized -- this is not fatal\n");
return;
- }
}
/* Now read the threadmap */
if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
{
/* This is not fatal -- just means I cant map command strings */
-
- printf("Can't read the thread map -- this is not fatal\n");
free(mapptr);
mapptr = 0;
- return;
}
- return;
}
}
+
+char *lookup_name(unsigned long addr)
+{
+ register int i;
+ register int start, last;
+
+
+ if (numFrameworks == 0 || addr < frameworkInfo[0].address || addr > frameworkInfo[numFrameworks].address)
+ return (0);
+
+ start = 0;
+ last = numFrameworks;
+
+ for (i = numFrameworks / 2; i >= 0 && i < numFrameworks; ) {
+
+ if (addr >= frameworkInfo[i].address && addr < frameworkInfo[i+1].address)
+ return(frameworkInfo[i].name);
+
+ if (addr >= frameworkInfo[i].address) {
+ start = i;
+ i = start + ((last - i) / 2);
+ } else {
+ last = i;
+ i = start + ((i - start) / 2);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * Comparison routines for sorting
+ */
+static int compareFrameworkAddress(const void *aa, const void *bb)
+{
+ LibraryInfo *a = (LibraryInfo *)aa;
+ LibraryInfo *b = (LibraryInfo *)bb;
+
+ if (a->address < b->address) return -1;
+ if (a->address == b->address) return 0;
+ return 1;
+}
+
+
+int scanline(char *inputstring,char **argv)
+{
+ int n = 0;
+ char **ap = argv, *p, *val;
+
+ for (p = inputstring; p != NULL; )
+ {
+ while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
+ *ap++ = val;
+ n++;
+ }
+ *ap = 0;
+ return n;
+}
+
+
+int ReadSegAddrTable()
+{
+ char buf[1024];
+
+ FILE *fd;
+ unsigned long frameworkAddress, frameworkDataAddress, previousFrameworkAddress;
+ char frameworkName[256];
+ char *tokens[64];
+ int ntokens;
+ char *substring,*ptr;
+ int founddylib = 0;
+ int i;
+
+
+ bzero(buf, sizeof(buf));
+ bzero(tokens, sizeof(tokens));
+
+ numFrameworks = 0;
+
+ if ((fd = fopen(seg_addr_table, "r")) == 0)
+ {
+ return 0;
+ }
+ fgets(buf, 1023, fd);
+
+ if (*buf == '#')
+ {
+ founddylib = 0;
+ frameworkName[0] = 0;
+ previousFrameworkAddress = 0;
+
+ while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2))
+ {
+ /*
+ * Get rid of EOL
+ */
+ buf[strlen(buf)-1] = 0;
+
+ if (strncmp(buf, "# dyld:", 7) == 0) {
+ /*
+ * the next line in the file will contain info about dyld
+ */
+ founddylib = 1;
+ continue;
+ }
+ /*
+ * This is a split library line: parse it into 3 tokens
+ */
+ ntokens = scanline(buf, tokens);
+
+ if (ntokens < 3)
+ continue;
+
+ frameworkAddress = strtoul(tokens[0], 0, 16);
+ frameworkDataAddress = strtoul(tokens[1], 0, 16);
+
+ if (founddylib) {
+ /*
+ * dyld entry is of a different form from the std split library
+ * it consists of a base address and a size instead of a code
+ * and data base address
+ */
+ frameworkInfo[numFrameworks].address = frameworkAddress;
+ frameworkInfo[numFrameworks+1].address = frameworkAddress + frameworkDataAddress;
+
+ frameworkInfo[numFrameworks].name = (char *)"dylib";
+ frameworkInfo[numFrameworks+1].name = (char *)0;
+
+ numFrameworks += 2;
+ founddylib = 0;
+
+ continue;
+ }
+
+ /*
+ * Make sure that we have 2 addresses and a path
+ */
+ if (!frameworkAddress)
+ continue;
+ if (!frameworkDataAddress)
+ continue;
+ if (*tokens[2] != '/')
+ continue;
+ if (frameworkAddress == previousFrameworkAddress)
+ continue;
+ previousFrameworkAddress = frameworkAddress;
+
+ /*
+ * Extract lib name from path name
+ */
+ if (substring = strrchr(tokens[2], '.'))
+ {
+ /*
+ * There is a ".": name is whatever is between the "/" around the "."
+ */
+ while ( *substring != '/') { /* find "/" before "." */
+ substring--;
+ }
+ substring++;
+ strcpy(frameworkName, substring); /* copy path from "/" */
+ substring = frameworkName;
+
+ while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
+ substring++;
+ *substring = 0;
+ }
+ else
+ {
+ /*
+ * No ".": take segment after last "/"
+ */
+ ptr = tokens[2];
+ substring = ptr;
+
+ while (*ptr)
+ {
+ if (*ptr == '/')
+ substring = ptr + 1;
+ ptr++;
+ }
+ strcpy(frameworkName, substring);
+ }
+ frameworkInfo[numFrameworks].address = frameworkAddress;
+ frameworkInfo[numFrameworks+1].address = frameworkDataAddress;
+
+ frameworkInfo[numFrameworks].name = (char *)malloc(strlen(frameworkName) + 1);
+ strcpy(frameworkInfo[numFrameworks].name, frameworkName);
+ frameworkInfo[numFrameworks+1].name = frameworkInfo[numFrameworks].name;
+
+ numFrameworks += 2;
+ }
+ }
+ frameworkInfo[numFrameworks].address = frameworkInfo[numFrameworks - 1].address + 0x800000;
+ frameworkInfo[numFrameworks].name = (char *)0;
+
+ fclose(fd);
+
+ qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);
+
+ return 1;
+}
+
+
+struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, int thread, double curtime)
+{
+ register struct diskio *dio;
+ register kd_threadmap *map;
+
+ if (dio = free_diskios)
+ free_diskios = dio->next;
+ else {
+ if ((dio = (struct diskio *)malloc(sizeof(struct diskio))) == NULL)
+ return (NULL);
+ }
+ dio->prev = NULL;
+
+ dio->type = type;
+ dio->bp = bp;
+ dio->dev = dev;
+ dio->blkno = blkno;
+ dio->iosize = io_size;
+ dio->issued_time = curtime;
+ dio->issuing_thread = thread;
+
+ if (map = find_thread_map(thread))
+ strcpy(dio->issuing_command, map->command);
+ else
+ strcpy(dio->issuing_command, "");
+
+ dio->next = busy_diskios;
+ if (dio->next)
+ dio->next->prev = dio;
+ busy_diskios = dio;
+
+ return (dio);
+}
+
+
+struct diskio *complete_diskio(int bp, int io_errno, int resid, int thread, double curtime)
+{
+ register struct diskio *dio;
+
+ for (dio = busy_diskios; dio; dio = dio->next) {
+ if (dio->bp == bp) {
+
+ if (dio == busy_diskios) {
+ if (busy_diskios = dio->next)
+ dio->next->prev = NULL;
+ } else {
+ if (dio->next)
+ dio->next->prev = dio->prev;
+ dio->prev->next = dio->next;
+ }
+ dio->iosize -= resid;
+ dio->io_errno = io_errno;
+ dio->completed_time = curtime;
+ dio->completion_thread = thread;
+
+ return (dio);
+ }
+ }
+ return ((struct diskio *)0);
+}
+
+
+void free_diskio(struct diskio *dio)
+{
+ dio->next = free_diskios;
+ free_diskios = dio;
+}
+
+
+void print_diskio(struct diskio *dio)
+{
+ register char *p;
+ struct th_info *ti;
+
+ switch (dio->type) {
+
+ case P_RdMeta:
+ p = " RdMeta";
+ break;
+ case P_WrMeta:
+ p = " WrMeta";
+ break;
+ case P_RdData:
+ p = " RdData";
+ break;
+ case P_WrData:
+ p = " WrData";
+ break;
+ case P_PgIn:
+ p = " PgIn";
+ break;
+ case P_PgOut:
+ p = " PgOut";
+ break;
+ case P_RdMetaAsync:
+ p = " RdMeta[async]";
+ break;
+ case P_WrMetaAsync:
+ p = " WrMeta[async]";
+ break;
+ case P_RdDataAsync:
+ p = " RdData[async]";
+ break;
+ case P_WrDataAsync:
+ p = " WrData[async]";
+ break;
+ case P_PgInAsync:
+ p = " PgIn[async]";
+ break;
+ case P_PgOutAsync:
+ p = " PgOut[async]";
+ break;
+
+ }
+ format_print(NULL, p, dio->issuing_thread, dio->type, 0, 0, 0, 7, dio->completed_time, dio->issued_time, 1, "", dio);
+}
+
+
+cache_disk_names()
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ struct diskrec *dnp;
+
+
+ if ((dirp = opendir("/dev")) == NULL)
+ return;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MAXPATHLEN];
+
+ if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
+ continue;
+ sprintf(nbuf, "%s/%s", "/dev", dir->d_name);
+
+ if (stat(nbuf, &st) < 0)
+ continue;
+
+ if ((dnp = (struct diskrec *)malloc(sizeof(struct diskrec))) == NULL)
+ continue;
+
+ if ((dnp->diskname = (char *)malloc(dir->d_namlen + 1)) == NULL) {
+ free(dnp);
+ continue;
+ }
+ strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
+ dnp->diskname[dir->d_namlen] = 0;
+ dnp->dev = st.st_rdev;
+
+ dnp->next = disk_list;
+ disk_list = dnp;
+ }
+ (void) closedir(dirp);
+}
+
+
+char *find_disk_name(int dev)
+{
+ struct diskrec *dnp;
+
+ if (dev == NFS_DEV)
+ return ("NFS");
+
+ for (dnp = disk_list; dnp; dnp = dnp->next) {
+ if (dnp->dev == dev)
+ return (dnp->diskname);
+ }
+ return ("NOTFOUND");
+}
#CHFLAGS = /usr/bin/chflags
#after_install::
# $(CHFLAGS) schg $(DSTROOT)$(INSTALLDIR)/$(NAME)
-
+after_install:
+ mkdir -p "$(DSTROOT)/usr/share/man/man8"
+ install -c -m 644 init.8 "$(DSTROOT)/usr/share/man/man8/init.8"
+ ln -f "$(DSTROOT)/usr/share/man/man8/init.8" "$(DSTROOT)/usr/share/man/man8/securelevel.8"
# can be added to Compiler Flags to provide Secure login
# -DSECURE LIBS = -lutil
OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
+AFTER_INSTALL = after_install
{
argv[1] = _PATH_RUNCOM_BOOT;
argv[2] = requested_transition == single_user
- ? "singleuser" : 0;
+ ? "singleuser" : "multiuser";
}
else /* runcom_mode != BOOT_SCRIPT */
{
CFILES = iostat.c
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble iostat.8\
- names.c
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble iostat.8
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
PROF_LIBS = $(LIBS)
+FRAMEWORKS = -framework CoreFoundation -framework IOKit
NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
# Ownership and permissions of files installed by 'install' target
#INSTALL_AS_USER = root # User to chown app to
-INSTALL_AS_GROUP = kmem # Group to chgrp app to
-INSTALL_PERMISSIONS = 2555 # If set, 'install' chmod's executable to this
+#INSTALL_AS_GROUP = kmem # Group to chgrp app to
+#INSTALL_PERMISSIONS = 2555 # If set, 'install' chmod's executable to this
# Options to strip for bundles, apps with bundles, and apps without bundles,
# respectively.
{
DOCICONFILES = ();
FILESTABLE = {
+ FRAMEWORKS = (CoreFoundation.framework, IOKit.framework);
C_FILES = ();
H_FILES = ();
OTHER_LIBS = ();
OTHER_LINKED = (iostat.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, iostat.8, names.c);
+ OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, iostat.8);
PRECOMPILED_HEADERS = ();
PROJECT_HEADERS = ();
PUBLIC_HEADERS = ();
+.\"
+.\" Copyright (c) 1997 Kenneth D. Merry.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.sbin/iostat/iostat.8,v 1.20 2001/08/07 13:59:48 ru Exp $
+.\"
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\"
.\" @(#)iostat.8 8.1 (Berkeley) 6/6/93
.\"
-.Dd June 6, 1993
+.Dd September 27, 2001
.Dt IOSTAT 8
-.Os BSD 4
+.Os
.Sh NAME
.Nm iostat
.Nd report
.Tn I/O
statistics
.Sh SYNOPSIS
-.Nm iostat
+.Nm
+.Op Fl CdKIoT?\&
.Op Fl c Ar count
-.Op Fl M Ar core
-.Op Fl N Ar system
+.Op Fl n Ar devs
.Op Fl w Ar wait
.Op Ar drives
.Sh DESCRIPTION
.Nm Iostat
displays kernel
.Tn I/O
-statistics on terminal, disk and cpu
-operations.
+statistics on terminal, device and cpu operations.
+The first statistics that are printed are averaged over the system uptime.
+To get information about the current activity, a suitable wait time should
+be specified, so that the subsequent sets of printed statistics will be
+averaged over that time.
.Pp
The options are as follows:
.Bl -tag -width flag
Repeat the display
.Ar count
times.
-The first display is for the time since a reboot and each subsequent
-report is for the time period since the last display.
If no
.Ar wait
interval is specified, the default is 1 second.
-.It Fl M
-Extract values associated with the name list from the specified core
-instead of the default
-.Dq Pa /dev/kmem .
-.It Fl N
-Extract the name list from the specified system instead of the default
-.Dq Pa /vmunix .
+.It Fl C
+Display CPU statistics.
+This is on by default, unless
+.Fl d
+is specified.
+.It Fl d
+Display only device statistics.
+If this flag is turned on, only device statistics will be displayed, unless
+.Fl C
+or
+.Fl T
+is also specfied to enable the display of CPU or TTY statistics.
+.It Fl I
+Display total statstics for a given time period, rather than average
+statistics for each second during that time period.
+.It Fl K
+In the blocks transfered display (-o), display block count in kilobytes rather
+then the device native block size.
+.It Fl n
+Display up to
+.Ar devs
+number of devices.
+.Nm
+will display fewer devices if there aren't
+.Ar devs
+devices present.
+.It Fl o
+Display old-style
+.Nm
+device statistics.
+Sectors per second, transfers per second, and miliseconds per seek are
+displayed.
+If
+.Fl I
+is specified, total blocks/sectors, total transfers, and
+miliseconds per seek are displayed.
+.It Fl T
+Display TTY statistics.
+This is on by default, unless
+.Fl d
+is specified.
.It Fl w
Pause
.Ar wait
If no repeat
.Ar count
is specified, the default is infinity.
+.It Fl ?\&
+Display a usage statement and exit.
.El
.Pp
.Nm Iostat
.It tout
characters written to terminals
.El
-.It disks
-Disk operations (this field is system dependent).
-The header of the field is the disk name and unit number.
-If more than four disk drives are configured in the system,
-.Nm iostat
-displays only the first four drives.
+.It devices
+Device operations.
+The header of the field is the device name and unit number.
+.Nm
+will display as many devices as will fit in a standard 80 column screen, or
+the maximum number of devices in the system, whichever is smaller.
+If
+.Fl n
+is specified on the command line,
+.Nm
+will display the smaller of the
+requested number of devices, and the maximum number of devices in the system.
To force
-.Nm iostat
+.Nm
to display specific drives, their names may be supplied on the command
line.
+.Nm
+will not display more devices than will fit in an 80 column screen, unless
+the
+.Fl n
+argument is given on the command line to specify a maximum number of
+devices to display, or the list of specified devices exceeds 80 columns.
+If fewer devices are specified on the command line than will fit in an 80
+column screen,
+.Nm
+will show only the specified devices.
+.Pp
+The standard
+.Nm
+device display shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It tps
+transfers per second
+.It MB/s
+megabytes per second
+.El
+.Pp
+The standard
+.Nm
+device display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It xfrs
+total number of transfers
+.It MB
+total number of megabytes transferred
+.El
+.Pp
+The old-style
+.Nm
+display (using
+.Fl o )
+shows the following statistics:
.Pp
.Bl -tag -width indent -compact
.It sps
.It tps
transfers per second
.It msps
-milliseconds per average seek (including implied
-seeks and rotational latency)
+average milliseconds per transaction
+.El
+.Pp
+The old-style
+.Nm
+display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It blk
+total blocks/sectors transferred
+.It xfr
+total transfers
+.It msps
+average milliseconds per transaction
.El
.It cpu
.Bl -tag -width indent -compact
.It \&us
% of cpu time in user mode
-.It \&ni
-% of cpu time in user mode running niced processes
.It \&sy
% of cpu time in system mode
.It \&id
% of cpu time in idle mode
.El
.El
-.Sh FILES
-.Bl -tag -width /dev/kmem -compact
-.It Pa /vmunix
-Default kernel namelist.
-.It Pa /dev/kmem
-Default memory file.
-.El
+.Sh EXAMPLES
+.Dl iostat -w 1 disk0 disk2
+.Pp
+Display statistics for the first and third disk devices device every
+second ad infinitum.
+.Pp
+.Dl iostat -c 2
+.Pp
+Display the statistics for the first four devices in the system twice, with
+a one second display interval.
+.Pp
+.Dl iostat -Iw 3
+.Pp
+Display total statistics every three seconds ad infinitum.
+.Pp
+.Dl iostat -odICTw 2 -c 9
+.Pp
+Display total statistics using the old-style output format 9 times, with
+a two second interval between each measurement/display.
+The
+.Fl d
+flag generally disables the TTY and CPU displays, but since the
+.Fl T
+and
+.Fl C
+flags are given, the TTY and CPU displays will be displayed.
.Sh SEE ALSO
.Xr fstat 1 ,
.Xr netstat 1 ,
.Xr nfsstat 1 ,
-.Xr \&ps 1 ,
-.Xr systat 1 ,
-.Xr vmstat 1 ,
-.Xr pstat 8
+.Xr ps 1 ,
+.Xr pstat 8 ,
.Pp
The sections starting with ``Interpreting system activity'' in
.%T "Installing and Operating 4.3BSD" .
+.Sh HISTORY
+This version of
+.Nm
+first appeared in
+.Nm FreeBSD 3.0 .
*
* @APPLE_LICENSE_HEADER_END@
*/
+/*
+ * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/iostat/iostat.c,v 1.22 2001/09/01 07:40:19 kris Exp $
+ */
+/*
+ * Parts of this program are derived from the original FreeBSD iostat
+ * program:
+ */
/*-
* Copyright (c) 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*
+ * Ideas for the new iostat statistics output modes taken from the NetBSD
+ * version of iostat:
+ */
+/*
+ * Copyright (c) 1996 John M. Vinopal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project
+ * by John M. Vinopal.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1986, 1991, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95";
-#endif /* not lint */
+#define IOKIT 1 /* to get io_name_t in device_types.h */
#include <sys/param.h>
-#include <sys/buf.h>
-#include <sys/dkstat.h>
+#include <sys/sysctl.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
#include <err.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <kvm.h>
-#include <limits.h>
-#include <nlist.h>
-#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-struct nlist namelist[] = {
-#define X_DK_TIME 0
- { "_dk_time" },
-#define X_DK_XFER 1
- { "_dk_xfer" },
-#define X_DK_WDS 2
- { "_dk_wds" },
-#define X_TK_NIN 3
- { "_tk_nin" },
-#define X_TK_NOUT 4
- { "_tk_nout" },
-#define X_DK_SEEK 5
- { "_dk_seek" },
-#define X_CP_TIME 6
- { "_cp_time" },
-#define X_DK_WPMS 7
- { "_dk_wpms" },
-#define X_HZ 8
- { "_hz" },
-#define X_STATHZ 9
- { "_stathz" },
-#define X_DK_NDRIVE 10
- { "_dk_ndrive" },
-#define X_END 10
-#if defined(hp300) || defined(luna68k)
-#define X_HPDINIT (X_END+1)
- { "_hp_dinit" },
-#endif
-#ifdef mips
-#define X_SCSI_DINIT (X_END+1)
- { "_scsi_dinit" },
-#endif
-#ifdef tahoe
-#define X_VBDINIT (X_END+1)
- { "_vbdinit" },
-#endif
-#ifdef vax
- { "_mbdinit" },
-#define X_MBDINIT (X_END+1)
- { "_ubdinit" },
-#define X_UBDINIT (X_END+2)
-#endif
- { NULL },
+#define MAXDRIVES 16 /* most drives we will record */
+#define MAXDRIVENAME 31 /* largest drive name we allow */
+
+struct drivestats {
+ io_registry_entry_t driver;
+ char name[MAXDRIVENAME + 1];
+ u_int64_t blocksize;
+ u_int64_t total_bytes;
+ u_int64_t total_transfers;
+ u_int64_t total_time;
};
-struct _disk {
- long cp_time[CPUSTATES];
- long *dk_time;
- long *dk_wds;
- long *dk_seek;
- long *dk_xfer;
- long tk_nin;
- long tk_nout;
-} cur, last;
+static struct drivestats drivestat[MAXDRIVES];
+
+static struct timeval cur_time, last_time;
+
+struct statinfo {
+ long tk_nin;
+ long tk_nout;
+ host_cpu_load_info_data_t load;
+};
+
+static struct statinfo cur, last;
+
+static mach_port_t host_priv_port;
+static mach_port_t masterPort;
+
+static int num_devices;
+static int maxshowdevs;
+static int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
+static volatile sig_atomic_t phdr_flag = 0;
-kvm_t *kd;
-double etime;
-long *dk_wpms;
-int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
-char **dr_name;
+/* local function declarations */
+static void usage(void);
+static void phdr(int signo);
+static void do_phdr();
+static void devstats(int perf_select, long double etime, int havelast);
+static void cpustats(void);
+static int readvar(const char *name, void *ptr, size_t len);
-#define nlread(x, v) \
- kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
+static int record_all_devices(void);
+static int record_one_device(char *name);
+static int record_device(io_registry_entry_t drive);
-#include "names.c" /* XXX */
+static long double compute_etime(struct timeval cur_time,
+ struct timeval prev_time);
-void cpustats __P((void));
-void dkstats __P((void));
-void phdr __P((int));
-void usage __P((void));
+static void
+usage(void)
+{
+ /*
+ * We also support the following 'traditional' syntax:
+ * iostat [drives] [wait [count]]
+ * This isn't mentioned in the man page, or the usage statement,
+ * but it is supported.
+ */
+ fprintf(stderr, "usage: iostat [-CdIKoT?] [-c count] [-n devs]\n"
+ "\t [-w wait] [drives]\n");
+}
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char **argv)
{
- register int i;
- long tmp;
- int ch, hdrcnt, reps, interval, stathz, ndrives;
- char **cp, *memf, *nlistf, buf[30];
- char errbuf[_POSIX2_LINE_MAX];
-
- interval = reps = 0;
- nlistf = memf = NULL;
- while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
- switch(ch) {
- case 'c':
- if ((reps = atoi(optarg)) <= 0)
- errx(1, "repetition count <= 0.");
- break;
- case 'M':
- memf = optarg;
- break;
- case 'N':
- nlistf = optarg;
- break;
- case 'w':
- if ((interval = atoi(optarg)) <= 0)
- errx(1, "interval <= 0.");
- break;
- case '?':
- default:
- usage();
+ int c;
+ int hflag = 0, cflag = 0, wflag = 0, nflag = 0;
+ int count = 0, waittime = 0;
+ int headercount;
+ int num_devices_specified;
+ int havelast = 0;
+
+ maxshowdevs = 3;
+
+ while ((c = getopt(argc, argv, "c:CdIKM:n:oTw:?")) != -1) {
+ switch(c) {
+ case 'c':
+ cflag++;
+ count = atoi(optarg);
+ if (count < 1)
+ errx(1, "count %d is < 1", count);
+ break;
+ case 'C':
+ Cflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'I':
+ Iflag++;
+ break;
+ case 'K':
+ Kflag++;
+ break;
+ case 'n':
+ nflag++;
+ maxshowdevs = atoi(optarg);
+ if (maxshowdevs < 0)
+ errx(1, "number of devices %d is < 0",
+ maxshowdevs);
+ break;
+ case 'o':
+ oflag++;
+ break;
+ case 'T':
+ Tflag++;
+ break;
+ case 'w':
+ wflag++;
+ waittime = atoi(optarg);
+ if (waittime < 1)
+ errx(1, "wait time is < 1");
+ break;
+ default:
+ usage();
+ exit(1);
+ break;
}
+ }
+
argc -= optind;
argv += optind;
/*
- * Discard setgid privileges if not the running kernel so that bad
- * guys can't print interesting stuff from kernel memory.
+ * Get the Mach private port.
+ */
+ host_priv_port = mach_host_self();
+
+ /*
+ * Get the I/O Kit communication handle.
+ */
+ IOMasterPort(bootstrap_port, &masterPort);
+
+ /*
+ * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is
+ * greater than 0, they may be 0 or non-zero.
*/
- if (nlistf != NULL || memf != NULL)
- setgid(getgid());
-
- kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
- if (kd == 0)
- errx(1, "kvm_openfiles: %s", errbuf);
- if (kvm_nlist(kd, namelist) == -1)
- errx(1, "kvm_nlist: %s", kvm_geterr(kd));
- if (namelist[X_DK_NDRIVE].n_type == 0)
- errx(1, "dk_ndrive not found in namelist");
- (void)nlread(X_DK_NDRIVE, dk_ndrive);
- if (dk_ndrive <= 0)
- errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
-
- cur.dk_time = calloc(dk_ndrive, sizeof(long));
- cur.dk_wds = calloc(dk_ndrive, sizeof(long));
- cur.dk_seek = calloc(dk_ndrive, sizeof(long));
- cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
- last.dk_time = calloc(dk_ndrive, sizeof(long));
- last.dk_wds = calloc(dk_ndrive, sizeof(long));
- last.dk_seek = calloc(dk_ndrive, sizeof(long));
- last.dk_xfer = calloc(dk_ndrive, sizeof(long));
- dr_select = calloc(dk_ndrive, sizeof(int));
- dr_name = calloc(dk_ndrive, sizeof(char *));
- dk_wpms = calloc(dk_ndrive, sizeof(long));
-
- for (i = 0; i < dk_ndrive; i++) {
- (void)sprintf(buf, "dk%d", i);
- dr_name[i] = strdup(buf);
+ if (dflag == 0) {
+ Cflag = 1;
+ Tflag = 1;
}
- if (!read_names())
- exit(1);
- (void)nlread(X_HZ, hz);
- (void)nlread(X_STATHZ, stathz);
- if (stathz)
- hz = stathz;
- (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
- dk_ndrive * sizeof(dk_wpms));
/*
- * Choose drives to be displayed. Priority goes to (in order) drives
- * supplied as arguments and default drives. If everything isn't
- * filled in and there are drives not taken care of, display the first
- * few that fit.
- *
- * The backward compatibility #ifdefs permit the syntax:
- * iostat [ drives ] [ interval [ count ] ]
+ * Figure out how many devices we should display if not given
+ * an explicit value.
+ */
+ if (nflag == 0) {
+ if (oflag > 0) {
+ if ((dflag > 0) && (Cflag == 0) && (Tflag == 0))
+ maxshowdevs = 5;
+ else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0))
+ maxshowdevs = 5;
+ else
+ maxshowdevs = 4;
+ } else {
+ if ((dflag > 0) && (Cflag == 0))
+ maxshowdevs = 4;
+ else
+ maxshowdevs = 3;
+ }
+ }
+
+ /*
+ * If the user specified any devices on the command line, record
+ * them for monitoring.
*/
-#define BACKWARD_COMPATIBILITY
- for (ndrives = 0; *argv; ++argv) {
-#ifdef BACKWARD_COMPATIBILITY
+ for (num_devices_specified = 0; *argv; ++argv) {
if (isdigit(**argv))
break;
-#endif
- for (i = 0; i < dk_ndrive; i++) {
- if (strcmp(dr_name[i], *argv))
- continue;
- dr_select[i] = 1;
- ++ndrives;
- }
+ if (record_one_device(*argv))
+ errx(1, "can't record '%s' for monitoring");
+ num_devices_specified++;
}
-#ifdef BACKWARD_COMPATIBILITY
+ if (nflag == 0 && maxshowdevs < num_devices_specified)
+ maxshowdevs = num_devices_specified;
+
+ /* if no devices were specified, pick them ourselves */
+ if ((num_devices_specified == 0) && record_all_devices())
+ err(1, "can't find any devices to display");
+
+ /*
+ * Look for the traditional wait time and count arguments.
+ */
if (*argv) {
- interval = atoi(*argv);
- if (*++argv)
- reps = atoi(*argv);
- }
-#endif
-
- if (interval) {
- if (!reps)
- reps = -1;
- } else
- if (reps)
- interval = 1;
-
- for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
- if (dr_select[i] || dk_wpms[i] == 0)
- continue;
- for (cp = defdrives; *cp; cp++)
- if (strcmp(dr_name[i], *cp) == 0) {
- dr_select[i] = 1;
- ++ndrives;
- break;
- }
- }
- for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
- if (dr_select[i])
- continue;
- dr_select[i] = 1;
- ++ndrives;
+ waittime = atoi(*argv);
+
+ /* Let the user know he goofed, but keep going anyway */
+ if (wflag != 0)
+ warnx("discarding previous wait interval, using"
+ " %d instead", waittime);
+ wflag++;
+
+ if (*++argv) {
+ count = atoi(*argv);
+ if (cflag != 0)
+ warnx("discarding previous count, using %d"
+ " instead", count);
+ cflag++;
+ } else
+ count = -1;
}
+ /*
+ * If the user specified a count, but not an interval, we default
+ * to an interval of 1 second.
+ */
+ if ((wflag == 0) && (cflag > 0))
+ waittime = 1;
+
+ /*
+ * If the user specified a wait time, but not a count, we want to
+ * go on ad infinitum. This can be redundant if the user uses the
+ * traditional method of specifying the wait, since in that case we
+ * already set count = -1 above. Oh well.
+ */
+ if ((wflag > 0) && (cflag == 0))
+ count = -1;
+
+ cur.tk_nout = 0;
+ cur.tk_nin = 0;
+
+ /*
+ * Set the busy time to the system boot time, so the stats are
+ * calculated since system boot.
+ */
+ if (readvar("kern.boottime", &cur_time, sizeof(cur_time)) != 0)
+ exit(1);
+
+ /*
+ * If the user stops the program (control-Z) and then resumes it,
+ * print out the header again.
+ */
(void)signal(SIGCONT, phdr);
- for (hdrcnt = 1;;) {
- if (!--hdrcnt) {
- phdr(0);
- hdrcnt = 20;
+ for (headercount = 1;;) {
+ long tmp;
+ long double etime;
+
+ if (Tflag > 0) {
+ if ((readvar("kern.tty_nin", &cur.tk_nin,
+ sizeof(cur.tk_nin)) != 0)
+ || (readvar("kern.tty_nout",
+ &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) {
+ Tflag = 0;
+ warnx("disabling TTY statistics");
+ }
+ }
+
+ if (phdr_flag) {
+ phdr_flag = 0;
+ do_phdr();
}
- (void)kvm_read(kd, namelist[X_DK_TIME].n_value,
- cur.dk_time, dk_ndrive * sizeof(long));
- (void)kvm_read(kd, namelist[X_DK_XFER].n_value,
- cur.dk_xfer, dk_ndrive * sizeof(long));
- (void)kvm_read(kd, namelist[X_DK_WDS].n_value,
- cur.dk_wds, dk_ndrive * sizeof(long));
- (void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
- cur.dk_seek, dk_ndrive * sizeof(long));
- (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
- &cur.tk_nin, sizeof(cur.tk_nin));
- (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
- &cur.tk_nout, sizeof(cur.tk_nout));
- (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
- cur.cp_time, sizeof(cur.cp_time));
- for (i = 0; i < dk_ndrive; i++) {
- if (!dr_select[i])
- continue;
-#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
- X(dk_xfer);
- X(dk_seek);
- X(dk_wds);
- X(dk_time);
+
+ if (!--headercount) {
+ do_phdr();
+ headercount = 20;
}
- tmp = cur.tk_nin;
- cur.tk_nin -= last.tk_nin;
- last.tk_nin = tmp;
- tmp = cur.tk_nout;
- cur.tk_nout -= last.tk_nout;
- last.tk_nout = tmp;
- etime = 0;
- for (i = 0; i < CPUSTATES; i++) {
- X(cp_time);
- etime += cur.cp_time[i];
+
+ last_time = cur_time;
+ gettimeofday(&cur_time, NULL);
+
+ if (Tflag > 0) {
+ tmp = cur.tk_nin;
+ cur.tk_nin -= last.tk_nin;
+ last.tk_nin = tmp;
+ tmp = cur.tk_nout;
+ cur.tk_nout -= last.tk_nout;
+ last.tk_nout = tmp;
}
+
+ etime = compute_etime(cur_time, last_time);
+
if (etime == 0.0)
etime = 1.0;
- etime /= (float)hz;
- (void)printf("%4.0f%5.0f",
- cur.tk_nin / etime, cur.tk_nout / etime);
- dkstats();
- cpustats();
- (void)printf("\n");
- (void)fflush(stdout);
- if (reps >= 0 && --reps <= 0)
+ if (Tflag > 0)
+ printf("%4.0Lf%5.0Lf", cur.tk_nin / etime,
+ cur.tk_nout / etime);
+
+ devstats(hflag, etime, havelast);
+
+ if (Cflag > 0)
+ cpustats();
+
+ printf("\n");
+ fflush(stdout);
+
+ if (count >= 0 && --count <= 0)
break;
- (void)sleep(interval);
+
+ sleep(waittime);
+ havelast = 1;
}
+
exit(0);
}
-/* ARGUSED */
-void
-phdr(signo)
- int signo;
+static void
+phdr(int signo)
+{
+
+ phdr_flag = 1;
+}
+
+static void
+do_phdr()
{
register int i;
- (void)printf(" tty");
- for (i = 0; i < dk_ndrive; i++)
- if (dr_select[i])
- (void)printf(" %3.3s ", dr_name[i]);
- (void)printf(" cpu\n tin tout");
- for (i = 0; i < dk_ndrive; i++)
- if (dr_select[i])
- (void)printf(" sps tps msps ");
- (void)printf(" us ni sy in id\n");
+ if (Tflag > 0)
+ (void)printf(" tty");
+
+ for (i = 0; (i < num_devices); i++){
+ if (oflag > 0)
+ (void)printf("%12.6s ", drivestat[i].name);
+ else
+ printf("%15.6s ", drivestat[i].name);
+ }
+
+ if (Cflag > 0)
+ (void)printf(" cpu\n");
+ else
+ (void)printf("\n");
+
+ if (Tflag > 0)
+ (void)printf(" tin tout");
+
+ for (i=0; i < num_devices; i++){
+ if (oflag > 0) {
+ if (Iflag == 0)
+ (void)printf(" sps tps msps ");
+ else
+ (void)printf(" blk xfr msps ");
+ } else {
+ if (Iflag == 0)
+ printf(" KB/t tps MB/s ");
+ else
+ printf(" KB/t xfrs MB ");
+ }
+ }
+
+ if (Cflag > 0)
+ (void)printf(" us sy id\n");
+ else
+ printf("\n");
}
-void
-dkstats()
+static void
+devstats(int perf_select, long double etime, int havelast)
{
- register int dn;
- double atime, itime, msps, words, xtime;
-
- for (dn = 0; dn < dk_ndrive; ++dn) {
- if (!dr_select[dn])
- continue;
- words = cur.dk_wds[dn] * 32; /* words xfer'd */
- (void)printf("%4.0f", /* sectors */
- words / (DEV_BSIZE / 2) / etime);
-
- (void)printf("%4.0f", cur.dk_xfer[dn] / etime);
-
- if (dk_wpms[dn] && cur.dk_xfer[dn]) {
- atime = cur.dk_time[dn]; /* ticks disk busy */
- atime /= (float)hz; /* ticks to seconds */
- xtime = words / dk_wpms[dn]; /* transfer time */
- itime = atime - xtime; /* time not xfer'ing */
- if (itime < 0)
- msps = 0;
+ CFNumberRef number;
+ CFDictionaryRef properties;
+ CFDictionaryRef statistics;
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ u_int64_t value;
+ u_int64_t total_bytes, total_transfers, total_blocks, total_time;
+ u_int64_t interval_bytes, interval_transfers, interval_blocks;
+ u_int64_t interval_time;
+ long double interval_mb;
+ long double blocks_per_second, ms_per_transaction;
+ kern_return_t status;
+ int i;
+
+ for (i = 0; i < num_devices; i++) {
+
+ /*
+ * If the drive goes away, we may not get any properties
+ * for it. So take some defaults.
+ */
+ total_bytes = 0;
+ total_transfers = 0;
+ total_time = 0;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drivestat[i].driver,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ err(1, "device has no properties");
+
+ /* get statistics from properties */
+ statistics = (CFDictionaryRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
+ if (statistics) {
+
+ /*
+ * Get I/O volume.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+
+ /*
+ * Get I/O counts.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+
+ /*
+ * Get I/O time.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+
+ }
+ CFRelease(properties);
+
+ /*
+ * Compute delta values and stats.
+ */
+ interval_bytes = total_bytes - drivestat[i].total_bytes;
+ interval_transfers = total_transfers
+ - drivestat[i].total_transfers;
+ interval_time = total_time - drivestat[i].total_time;
+
+ /* update running totals, only once for -I */
+ if ((Iflag == 0) || (drivestat[i].total_bytes == 0)) {
+ drivestat[i].total_bytes = total_bytes;
+ drivestat[i].total_transfers = total_transfers;
+ drivestat[i].total_time = total_time;
+ }
+
+ interval_blocks = interval_bytes / drivestat[i].blocksize;
+ total_blocks = total_bytes / drivestat[i].blocksize;
+
+ blocks_per_second = interval_blocks / etime;
+ transfers_per_second = interval_transfers / etime;
+ mb_per_second = (interval_bytes / etime) / (1024 * 1024);
+
+ kb_per_transfer = (interval_transfers > 0) ?
+ ((long double)interval_bytes / interval_transfers)
+ / 1024 : 0;
+
+ /* times are in nanoseconds, convert to milliseconds */
+ ms_per_transaction = (interval_transfers > 0) ?
+ ((long double)interval_time / interval_transfers)
+ / 1000 : 0;
+
+ if (Kflag)
+ total_blocks = total_blocks * drivestat[i].blocksize
+ / 1024;
+
+ if (oflag > 0) {
+ int msdig = (ms_per_transaction < 100.0) ? 1 : 0;
+
+ if (Iflag == 0)
+ printf("%4.0Lf%4.0Lf%5.*Lf ",
+ blocks_per_second,
+ transfers_per_second,
+ msdig,
+ ms_per_transaction);
else
- msps = itime * 1000 / cur.dk_xfer[dn];
- } else
- msps = 0;
- (void)printf("%5.1f ", msps);
+ printf("%4.1qu%4.1qu%5.*Lf ",
+ interval_blocks,
+ interval_transfers,
+ msdig,
+ ms_per_transaction);
+ } else {
+ if (Iflag == 0)
+ printf(" %5.2Lf %3.0Lf %5.2Lf ",
+ kb_per_transfer,
+ transfers_per_second,
+ mb_per_second);
+ else {
+ interval_mb = interval_bytes;
+ interval_mb /= 1024 * 1024;
+
+ printf(" %5.2Lf %3.1qu %5.2Lf ",
+ kb_per_transfer,
+ interval_transfers,
+ interval_mb);
+ }
+ }
}
}
-void
-cpustats()
+static void
+cpustats(void)
{
- register int state;
+ mach_msg_type_number_t count;
+ kern_return_t status;
double time;
- time = 0;
- for (state = 0; state < CPUSTATES; ++state)
- time += cur.cp_time[state];
- for (state = 0; state < CPUSTATES; ++state)
- (void)printf("%3.0f",
- 100. * cur.cp_time[state] / (time ? time : 1));
+ /*
+ * Get CPU usage counters.
+ */
+ count = HOST_CPU_LOAD_INFO_COUNT;
+ status = host_statistics(host_priv_port, HOST_CPU_LOAD_INFO,
+ (host_info_t)&cur.load, &count);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't fetch CPU stats");
+
+ /*
+ * Make 'cur' fields relative, update 'last' fields to current values,
+ * calculate total elapsed time.
+ */
+ time = 0.0;
+ cur.load.cpu_ticks[CPU_STATE_USER]
+ -= last.load.cpu_ticks[CPU_STATE_USER];
+ last.load.cpu_ticks[CPU_STATE_USER]
+ += cur.load.cpu_ticks[CPU_STATE_USER];
+ time += cur.load.cpu_ticks[CPU_STATE_USER];
+ cur.load.cpu_ticks[CPU_STATE_SYSTEM]
+ -= last.load.cpu_ticks[CPU_STATE_SYSTEM];
+ last.load.cpu_ticks[CPU_STATE_SYSTEM]
+ += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ time += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ cur.load.cpu_ticks[CPU_STATE_IDLE]
+ -= last.load.cpu_ticks[CPU_STATE_IDLE];
+ last.load.cpu_ticks[CPU_STATE_IDLE]
+ += cur.load.cpu_ticks[CPU_STATE_IDLE];
+ time += cur.load.cpu_ticks[CPU_STATE_IDLE];
+
+ /*
+ * Print times.
+ */
+ printf("%3.0f",
+ rint(100. * cur.load.cpu_ticks[CPU_STATE_USER]
+ / (time ? time : 1)));
+ printf("%3.0f",
+ rint(100. * cur.load.cpu_ticks[CPU_STATE_SYSTEM]
+ / (time ? time : 1)));
+ printf("%3.0f",
+ rint(100. * cur.load.cpu_ticks[CPU_STATE_IDLE]
+ / (time ? time : 1)));
+}
+
+static int
+readvar(const char *name, void *ptr, size_t len)
+{
+ int oid[4];
+ int oidlen;
+
+ size_t nlen = len;
+
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
+ if (errno != ENOENT) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ /*
+ * XXX fallback code to deal with systems where
+ * sysctlbyname can't find "old" OIDs, should be removed.
+ */
+ if (!strcmp(name, "kern.boottime")) {
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_BOOTTIME;
+ oidlen = 2;
+ } else {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+
+ nlen = len;
+ if (sysctl(oid, oidlen, ptr, &nlen, NULL, 0) == -1) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ }
+ if (nlen != len) {
+ warnx("sysctl(%s): expected %lu, got %lu", name,
+ (unsigned long)len, (unsigned long)nlen);
+ return (1);
+ }
+ return (0);
}
-void
-usage()
+static long double
+compute_etime(struct timeval cur_time, struct timeval prev_time)
{
- (void)fprintf(stderr,
-"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
- exit(1);
+ struct timeval busy_time;
+ u_int64_t busy_usec;
+ long double etime;
+
+ timersub(&cur_time, &prev_time, &busy_time);
+
+ busy_usec = busy_time.tv_sec;
+ busy_usec *= 1000000;
+ busy_usec += busy_time.tv_usec;
+ etime = busy_usec;
+ etime /= 1000000;
+
+ return(etime);
+}
+
+/*
+ * Record all "whole" IOMedia objects as being interesting.
+ */
+static int
+record_all_devices(void)
+{
+ io_iterator_t drivelist;
+ io_registry_entry_t drive;
+ CFMutableDictionaryRef match;
+ int error, ndrives;
+ kern_return_t status;
+
+ /*
+ * Get an iterator for IOMedia objects.
+ */
+ match = IOServiceMatching("IOMedia");
+ CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
+ status = IOServiceGetMatchingServices(masterPort, match, &drivelist);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match whole IOMedia devices");
+
+ /*
+ * Scan all of the IOMedia objects, and for each
+ * object that has a parent IOBlockStorageDriver, save
+ * the object's name and the parent (from which we can
+ * fetch statistics).
+ *
+ * XXX What about RAID devices?
+ */
+ error = 1;
+ ndrives = 0;
+ while ((drive = IOIteratorNext(drivelist))
+ && (ndrives < maxshowdevs)) {
+ if (!record_device(drive)) {
+ error = 0;
+ ndrives++;
+ }
+ IOObjectRelease(drive);
+ }
+ IOObjectRelease(drivelist);
+
+ return(error);
+}
+
+/*
+ * Try to record the named device as interesting. It
+ * must be an IOMedia device.
+ */
+static int
+record_one_device(char *name)
+{
+ io_iterator_t drivelist;
+ io_registry_entry_t drive;
+ kern_return_t status;
+
+ /*
+ * Find the device.
+ */
+ status = IOServiceGetMatchingServices(masterPort,
+ IOBSDNameMatching(masterPort, kNilOptions, name),
+ &drivelist);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match '%s'", name);
+
+ /*
+ * Get the first match (should only be one)
+ */
+ if ((drive = IOIteratorNext(drivelist)) == NULL)
+ errx(1, "'%s' not found", name);
+ if (!IOObjectConformsTo(drive, "IOMedia"))
+ errx(1, "'%s' is not a storage device", name);
+
+ /*
+ * Record the device.
+ */
+ if (record_device(drive))
+ errx(1, "could not record '%s' for monitoring", name);
+
+ IOObjectRelease(drive);
+ IOObjectRelease(drivelist);
+
+ return(0);
+}
+
+/*
+ * Determine whether an IORegistryEntry refers to a valid
+ * I/O device, and if so, record it.
+ */
+static int
+record_device(io_registry_entry_t drive)
+{
+ io_registry_entry_t parent;
+ CFDictionaryRef properties;
+ CFStringRef name;
+ CFNumberRef number;
+ kern_return_t status;
+
+ /* get drive's parent */
+ status = IORegistryEntryGetParentEntry(drive,
+ kIOServicePlane, &parent);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no parent");
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
+ drivestat[num_devices].driver = parent;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no properties");
+
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+ CFStringGetCString(name, drivestat[num_devices].name,
+ MAXDRIVENAME, CFStringGetSystemEncoding());
+
+ /* get blocksize from properties */
+ number = (CFNumberRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOMediaPreferredBlockSizeKey));
+ CFNumberGetValue(number, kCFNumberSInt64Type,
+ &drivestat[num_devices].blocksize);
+
+ /* clean up, return success */
+ CFRelease(properties);
+ num_devices++;
+ return(0);
+ }
+
+ /* failed, don't keep parent */
+ IOObjectRelease(parent);
+ return(1);
}
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*-
- * Copyright (c) 1986, 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if !defined(hp300) && !defined(tahoe) && !defined(vax) && \
- !defined(luna68k) && !defined(mips)
-char *defdrives[] = { 0 };
-int
-read_names()
-{
- return 0;
-}
-#endif
-
-#if defined(hp300) || defined(luna68k)
-#if defined(hp300)
-#include <hp/dev/device.h>
-#else
-#include <luna68k/dev/device.h>
-#endif
-
-char *defdrives[] = { "sd0", "sd1", "sd2", "rd0", "rd1", "rd2", 0 };
-
-int
-read_names()
-{
- register char *p;
- register u_long hp;
- static char buf[BUFSIZ];
- struct hp_device hdev;
- struct driver hdrv;
- char name[10];
-
- hp = namelist[X_HPDINIT].n_value;
- if (hp == 0) {
- (void)fprintf(stderr,
- "disk init info not in namelist\n");
- return (0);
- }
- p = buf;
- for (;; hp += sizeof hdev) {
- (void)kvm_read(kd, hp, &hdev, sizeof hdev);
- if (hdev.hp_driver == 0)
- break;
- if (hdev.hp_dk < 0 || hdev.hp_alive == 0 ||
- hdev.hp_cdriver == 0)
- continue;
- (void)kvm_read(kd, (u_long)hdev.hp_driver, &hdrv, sizeof hdrv);
- (void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name);
- dr_name[hdev.hp_dk] = p;
- p += sprintf(p, "%s%d", name, hdev.hp_unit) + 1;
- }
- return (1);
-}
-#endif /* hp300 || luna68k */
-
-#ifdef tahoe
-#include <tahoe/vba/vbavar.h>
-
-char *defdrives[] = { "dk0", "dk1", "dk2", 0 };
-
-int
-read_names()
-{
- register char *p;
- struct vba_device udev, *up;
- struct vba_driver udrv;
- char name[10];
- static char buf[BUFSIZ];
-
- up = (struct vba_device *)namelist[X_VBDINIT].n_value;
- if (up == 0) {
- (void) fprintf(stderr,
- "disk init info not in namelist\n");
- return (0);
- }
- p = buf;
- for (;; up += sizeof udev) {
- (void)kvm_read(kd, up, &udev, sizeof udev);
- if (udev.ui_driver == 0)
- break;
- if (udev.ui_dk < 0 || udev.ui_alive == 0)
- continue;
- (void)kvm_read(kd, udev.ui_driver, &udrv, sizeof udrv);
- (void)kvm_read(kd, udrv.ud_dname, name, sizeof name);
- dr_name[udev.ui_dk] = p;
- p += sprintf(p, "%s%d", name, udev.ui_unit);
- }
- return (1);
-}
-#endif /* tahoe */
-
-#ifdef vax
-#include <vax/uba/ubavar.h>
-#include <vax/mba/mbavar.h>
-
-char *defdrives[] = { "hp0", "hp1", "hp2", 0 };
-
-int
-read_names()
-{
- register char *p;
- unsigned long mp, up;
- struct mba_device mdev;
- struct mba_driver mdrv;
- struct uba_device udev;
- struct uba_driver udrv;
- char name[10];
- static char buf[BUFSIZ];
-
- mp = namelist[X_MBDINIT].n_value;
- up = namelist[X_UBDINIT].n_value;
- if (mp == 0 && up == 0) {
- (void)fprintf(stderr,
- "disk init info not in namelist\n");
- return (0);
- }
- p = buf;
- if (mp)
- for (;; mp += sizeof mdev) {
- (void)kvm_read(kd, mp, &mdev, sizeof mdev);
- if (mdev.mi_driver == 0)
- break;
- if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
- continue;
- (void)kvm_read(kd, mdev.mi_driver, &mdrv, sizeof mdrv);
- (void)kvm_rea(kd, mdrv.md_dname, name, sizeof name);
- dr_name[mdev.mi_dk] = p;
- p += sprintf(p, "%s%d", name, mdev.mi_unit);
- }
- if (up)
- for (;; up += sizeof udev) {
- (void)kvm_read(kd, up, &udev, sizeof udev);
- if (udev.ui_driver == 0)
- break;
- if (udev.ui_dk < 0 || udev.ui_alive == 0)
- continue;
- (void)kvm_read(kd, udev.ui_driver, &udrv, sizeof udrv);
- (void)kvm_read(kd, udrv.ud_dname, name, sizeof name);
- dr_name[udev.ui_dk] = p;
- p += sprintf(p, "%s%d", name, udev.ui_unit);
- }
- return (1);
-}
-#endif /* vax */
-
-#ifdef sun
-#include <sundev/mbvar.h>
-
-int
-read_names()
-{
- static int once = 0;
- struct mb_device mdev;
- struct mb_driver mdrv;
- short two_char;
- char *cp = (char *) &two_char;
- register struct mb_device *mp;
-
- mp = (struct mb_device *)namelist[X_MBDINIT].n_value;
- if (mp == 0) {
- (void)fprintf(stderr,
- "disk init info not in namelist\n");
- return (0);
- }
- for (;; ++mp) {
- (void)kvm_read(kd, mp++, &mdev, sizeof(mdev));
- if (mdev.md_driver == 0)
- break;
- if (mdev.md_dk < 0 || mdev.md_alive == 0)
- continue;
- (void)kvm_read(kd, mdev.md_driver, &mdrv, sizeof(mdrv));
- (void)kvm_read(kd, mdrv.mdr_dname, &two_char, sizeof(two_char));
- (void)sprintf(dr_name[mdev.md_dk],
- "%c%c%d", cp[0], cp[1], mdev.md_unit);
- }
- return(1);
-}
-#endif /* sun */
-
-#if defined(mips)
-#include <pmax/dev/device.h>
-
-char *defdrives[] = { "rz0", "rz1", "rz2", "rz3", "rz4", "rz5", "rz6", 0 };
-
-int
-read_names()
-{
- register char *p;
- register u_long sp;
- static char buf[BUFSIZ];
- struct scsi_device sdev;
- struct driver hdrv;
- char name[10];
-
- sp = namelist[X_SCSI_DINIT].n_value;
- if (sp == 0) {
- (void)fprintf(stderr, "disk init info not in namelist\n");
- return (0);
- }
- p = buf;
- for (;; sp += sizeof sdev) {
- (void)kvm_read(kd, sp, &sdev, sizeof sdev);
- if (sdev.sd_driver == 0)
- break;
- if (sdev.sd_dk < 0 || sdev.sd_alive == 0 ||
- sdev.sd_cdriver == 0)
- continue;
- (void)kvm_read(kd, (u_long)sdev.sd_driver, &hdrv, sizeof hdrv);
- (void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name);
- dr_name[sdev.sd_dk] = p;
- p += sprintf(p, "%s%d", name, sdev.sd_unit) + 1;
- }
- return (1);
-}
-#endif /* mips */
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = kdump
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = kdump.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kdump.1\
+ mkioctls syscalls.c
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+WINDOWS_INSTALLDIR = /usr/bin
+PDO_UNIX_INSTALLDIR = /usr/bin
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+HEADER_PATHS = -I../ktrace.tproj
+NEXTSTEP_PB_CFLAGS = -DMACH_USER_API
+WINDOWS_PB_CFLAGS = -DMACH_USER_API
+PDO_UNIX_PB_CFLAGS = -DMACH_USER_API
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+VPATH += :../ktrace.tproj
+
+ioctl.c: mkioctls
+ $(SHELL) mkioctls -s /usr/include > $(SFILE_DIR)/ioctl.c
+
+install-man-page:
+ install -d $(DSTROOT)/usr/share/man/man1
+ install -c -m 444 kdump.1 $(DSTROOT)/usr/share/man/man1/kdump.1
--- /dev/null
+KTRACE_CFILES = subr.c
+GENERATED_CFILES = ioctl.c
+OTHER_INITIAL_DEPENDS = $(GENERATED_CFILES)
+OTHER_OFILES = $(GENERATED_CFILES:.c=.o) $(KTRACE_CFILES:.c=.o)
+OTHER_GENERATED_OFILES = $(VERS_OFILE)
+AFTER_INSTALL += install-man-page
+-include ../Makefile.include
--- /dev/null
+{
+ APPCLASS = NSApplication;
+ FILESTABLE = {
+ FRAMEWORKS = ();
+ HEADERSEARCH = (../ktrace.tproj);
+ H_FILES = ();
+ M_FILES = ();
+ OTHER_LIBS = ();
+ OTHER_LINKED = (kdump.c);
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ kdump.1,
+ mkioctls,
+ syscalls.c
+ );
+ };
+ LANGUAGE = English;
+ LOCALIZABLE_FILES = {};
+ NEXTSTEP_BUILDTOOL = make;
+ NEXTSTEP_COMPILEROPTIONS = "-DMACH_USER_API";
+ NEXTSTEP_INSTALLDIR = /usr/bin;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_MAINNIB = kdump;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = make;
+ PDO_UNIX_COMPILEROPTIONS = "-DMACH_USER_API";
+ PDO_UNIX_INSTALLDIR = /usr/bin;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_MAINNIB = kdump;
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = kdump;
+ PROJECTTYPE = Tool;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = make;
+ WINDOWS_COMPILEROPTIONS = "-DMACH_USER_API";
+ WINDOWS_INSTALLDIR = /usr/bin;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_MAINNIB = kdump;
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)kdump.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/kdump/kdump.1,v 1.5.2.2 2001/08/16 13:16:51 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt KDUMP 1
+.Os
+.Sh NAME
+.Nm kdump
+.Nd display kernel trace data
+.Sh SYNOPSIS
+.Nm
+.Op Fl dnlRT
+.Op Fl f Ar file
+.Op Fl m Ar maxdata
+.Op Fl t Op cnisuw
+.Sh DESCRIPTION
+The
+.Nm
+command displays the kernel trace files produced with
+.Xr ktrace 1
+in human readable format.
+By default, the file
+.Pa ktrace.out
+in the current directory is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl d
+Display all numbers in decimal.
+.It Fl f Ar file
+Display the specified file instead of
+.Pa ktrace.out .
+.It Fl l
+Loop reading the trace file, once the end-of-file is reached, waiting for
+more data.
+.It Fl m Ar maxdata
+Display at most
+.Ar maxdata
+bytes when decoding
+.Tn I/O .
+.It Fl n
+Suppress ad hoc translations.
+Normally
+.Nm
+tries to decode many system calls into a more human readable format.
+For example,
+.Xr ioctl 2
+values are replaced with the macro name and
+.Va errno
+values are replaced with the
+.Xr strerror 3
+string.
+Suppressing this feature yields a more consistent output format and is
+easily amenable to further processing.
+.It Fl R
+Display relative timestamps (time since previous entry).
+.It Fl T
+Display absolute timestamps for each entry (seconds since epoch).
+.It Fl t Ar cnisuw
+See the
+.Fl t
+option of
+.Xr ktrace 1 .
+.El
+.Sh SEE ALSO
+.Xr ktrace 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
--- /dev/null
+/*
+ * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/kdump/kdump.c,v 1.17 1999/12/29 05:05:33 peter Exp $";
+#endif /* not lint */
+
+#define KERNEL
+extern int errno;
+#include <sys/errno.h>
+#undef KERNEL
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/ktrace.h>
+#include <sys/ioctl.h>
+#include <sys/ptrace.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+#include "ktrace.h"
+
+int timestamp, decimal, fancy = 1, tail, maxdata;
+char *tracefile = DEF_TRACEFILE;
+struct ktr_header ktr_header;
+
+#define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, ktrlen, size;
+ register void *m;
+ int trpoints = ALL_POINTS;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1)
+ switch((char)ch) {
+ case 'f':
+ tracefile = optarg;
+ break;
+ case 'd':
+ decimal = 1;
+ break;
+ case 'l':
+ tail = 1;
+ break;
+ case 'm':
+ maxdata = atoi(optarg);
+ break;
+ case 'n':
+ fancy = 0;
+ break;
+ case 'R':
+ timestamp = 2; /* relative timestamp */
+ break;
+ case 'T':
+ timestamp = 1;
+ break;
+ case 't':
+ trpoints = getpoints(optarg);
+ if (trpoints < 0)
+ errx(1, "unknown trace point in %s", optarg);
+ break;
+ default:
+ usage();
+ }
+
+ if (argc > optind)
+ usage();
+
+ m = (void *)malloc(size = 1025);
+ if (m == NULL)
+ errx(1, "%s", strerror(ENOMEM));
+ if (!freopen(tracefile, "r", stdin))
+ err(1, "%s", tracefile);
+ while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
+ if (trpoints & (1<<ktr_header.ktr_type))
+ dumpheader(&ktr_header);
+ if ((ktrlen = ktr_header.ktr_len) < 0)
+ errx(1, "bogus length 0x%x", ktrlen);
+ if (ktrlen > size) {
+ m = (void *)realloc(m, ktrlen+1);
+ if (m == NULL)
+ errx(1, "%s", strerror(ENOMEM));
+ size = ktrlen;
+ }
+ if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
+ errx(1, "data too short");
+ if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
+ continue;
+ switch (ktr_header.ktr_type) {
+ case KTR_SYSCALL:
+ ktrsyscall((struct ktr_syscall *)m);
+ break;
+ case KTR_SYSRET:
+ ktrsysret((struct ktr_sysret *)m);
+ break;
+ case KTR_NAMEI:
+ ktrnamei(m, ktrlen);
+ break;
+ case KTR_GENIO:
+ ktrgenio((struct ktr_genio *)m, ktrlen);
+ break;
+ case KTR_PSIG:
+ ktrpsig((struct ktr_psig *)m);
+ break;
+ case KTR_CSW:
+ ktrcsw((struct ktr_csw *)m);
+ break;
+ case KTR_USER:
+ ktruser(ktrlen, m);
+ break;
+ }
+ if (tail)
+ (void)fflush(stdout);
+ }
+}
+
+fread_tail(buf, size, num)
+ char *buf;
+ int num, size;
+{
+ int i;
+
+ while ((i = fread(buf, size, num, stdin)) == 0 && tail) {
+ (void)sleep(1);
+ clearerr(stdin);
+ }
+ return (i);
+}
+
+dumpheader(kth)
+ struct ktr_header *kth;
+{
+ static char unknown[64];
+ static struct timeval prevtime, temp;
+ char *type;
+
+ switch (kth->ktr_type) {
+ case KTR_SYSCALL:
+ type = "CALL";
+ break;
+ case KTR_SYSRET:
+ type = "RET ";
+ break;
+ case KTR_NAMEI:
+ type = "NAMI";
+ break;
+ case KTR_GENIO:
+ type = "GIO ";
+ break;
+ case KTR_PSIG:
+ type = "PSIG";
+ break;
+ case KTR_CSW:
+ type = "CSW";
+ break;
+ case KTR_USER:
+ type = "USER";
+ break;
+ default:
+ (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type);
+ type = unknown;
+ }
+
+ (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm);
+ if (timestamp) {
+ if (timestamp == 2) {
+ temp = kth->ktr_time;
+ timevalsub(&kth->ktr_time, &prevtime);
+ prevtime = temp;
+ }
+ (void)printf("%ld.%06ld ",
+ kth->ktr_time.tv_sec, kth->ktr_time.tv_usec);
+ }
+ (void)printf("%s ", type);
+}
+
+#include <sys/syscall.h>
+#include "syscalls.c"
+int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]);
+
+static char *ptrace_ops[] = {
+ "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U",
+ "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE",
+ "PT_KILL", "PT_STEP", "PT_ATTACH", "PT_DETACH",
+};
+
+ktrsyscall(ktr)
+ register struct ktr_syscall *ktr;
+{
+ register narg = ktr->ktr_narg;
+ register register_t *ip;
+ char *ioctlname();
+
+ if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
+ (void)printf("[%d]", ktr->ktr_code);
+ else
+ (void)printf("%s", syscallnames[ktr->ktr_code]);
+ ip = &ktr->ktr_args[0];
+ if (narg) {
+ char c = '(';
+ if (fancy) {
+ if (ktr->ktr_code == SYS_ioctl) {
+ char *cp;
+ if (decimal)
+ (void)printf("(%ld", (long)*ip);
+ else
+ (void)printf("(%#lx", (long)*ip);
+ ip++;
+ narg--;
+ if ((cp = ioctlname(*ip)) != NULL)
+ (void)printf(",%s", cp);
+ else {
+ if (decimal)
+ (void)printf(",%ld", (long)*ip);
+ else
+ (void)printf(",%#lx ", (long)*ip);
+ }
+ c = ',';
+ ip++;
+ narg--;
+ } else if (ktr->ktr_code == SYS_ptrace) {
+ if (*ip < sizeof(ptrace_ops) /
+ sizeof(ptrace_ops[0]) && *ip >= 0)
+ (void)printf("(%s", ptrace_ops[*ip]);
+#ifdef PT_GETREGS
+ else if (*ip == PT_GETREGS)
+ (void)printf("(%s", "PT_GETREGS");
+#endif
+#ifdef PT_SETREGS
+ else if (*ip == PT_SETREGS)
+ (void)printf("(%s", "PT_SETREGS");
+#endif
+#ifdef PT_GETFPREGS
+ else if (*ip == PT_GETFPREGS)
+ (void)printf("(%s", "PT_GETFPREGS");
+#endif
+#ifdef PT_SETFPREGS
+ else if (*ip == PT_SETFPREGS)
+ (void)printf("(%s", "PT_SETFPREGS");
+#endif
+#ifdef PT_GETDBREGS
+ else if (*ip == PT_GETDBREGS)
+ (void)printf("(%s", "PT_GETDBREGS");
+#endif
+#ifdef PT_SETDBREGS
+ else if (*ip == PT_SETDBREGS)
+ (void)printf("(%s", "PT_SETDBREGS");
+#endif
+ else
+ (void)printf("(%ld", (long)*ip);
+ c = ',';
+ ip++;
+ narg--;
+ }
+ }
+ while (narg) {
+ if (decimal)
+ (void)printf("%c%ld", c, (long)*ip);
+ else
+ (void)printf("%c%#lx", c, (long)*ip);
+ c = ',';
+ ip++;
+ narg--;
+ }
+ (void)putchar(')');
+ }
+ (void)putchar('\n');
+}
+
+ktrsysret(ktr)
+ struct ktr_sysret *ktr;
+{
+ register register_t ret = ktr->ktr_retval;
+ register int error = ktr->ktr_error;
+ register int code = ktr->ktr_code;
+
+ if (code >= nsyscalls || code < 0)
+ (void)printf("[%d] ", code);
+ else
+ (void)printf("%s ", syscallnames[code]);
+
+ if (error == 0) {
+ if (fancy) {
+ (void)printf("%d", ret);
+ if (ret < 0 || ret > 9)
+ (void)printf("/%#lx", (long)ret);
+ } else {
+ if (decimal)
+ (void)printf("%ld", (long)ret);
+ else
+ (void)printf("%#lx", (long)ret);
+ }
+ } else if (error == ERESTART)
+ (void)printf("RESTART");
+ else if (error == EJUSTRETURN)
+ (void)printf("JUSTRETURN");
+ else {
+ (void)printf("-1 errno %d", ktr->ktr_error);
+ if (fancy)
+ (void)printf(" %s", strerror(ktr->ktr_error));
+ }
+ (void)putchar('\n');
+}
+
+ktrnamei(cp, len)
+ char *cp;
+{
+ (void)printf("\"%.*s\"\n", len, cp);
+}
+
+ktrgenio(ktr, len)
+ struct ktr_genio *ktr;
+{
+ register int datalen = len - sizeof (struct ktr_genio);
+ register char *dp = (char *)ktr + sizeof (struct ktr_genio);
+ register char *cp;
+ register int col = 0;
+ register width;
+ char visbuf[5];
+ static screenwidth = 0;
+
+ if (screenwidth == 0) {
+ struct winsize ws;
+
+ if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
+ ws.ws_col > 8)
+ screenwidth = ws.ws_col;
+ else
+ screenwidth = 80;
+ }
+ printf("fd %d %s %d byte%s\n", ktr->ktr_fd,
+ ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen,
+ datalen == 1 ? "" : "s");
+ if (maxdata && datalen > maxdata)
+ datalen = maxdata;
+ (void)printf(" \"");
+ col = 8;
+ for (;datalen > 0; datalen--, dp++) {
+ (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
+ cp = visbuf;
+ /*
+ * Keep track of printables and
+ * space chars (like fold(1)).
+ */
+ if (col == 0) {
+ (void)putchar('\t');
+ col = 8;
+ }
+ switch(*cp) {
+ case '\n':
+ col = 0;
+ (void)putchar('\n');
+ continue;
+ case '\t':
+ width = 8 - (col&07);
+ break;
+ default:
+ width = strlen(cp);
+ }
+ if (col + width > (screenwidth-2)) {
+ (void)printf("\\\n\t");
+ col = 8;
+ }
+ col += width;
+ do {
+ (void)putchar(*cp++);
+ } while (*cp);
+ }
+ if (col == 0)
+ (void)printf(" ");
+ (void)printf("\"\n");
+}
+
+char *signames[] = {
+ "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */
+ "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */
+ "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */
+ "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */
+ "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */
+ "USR2", NULL, /* 31 - 32 */
+};
+
+ktrpsig(psig)
+ struct ktr_psig *psig;
+{
+ (void)printf("SIG%s ", signames[psig->signo]);
+ if (psig->action == SIG_DFL)
+ (void)printf("SIG_DFL\n");
+ else
+ (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
+ (u_long)psig->action, psig->mask, psig->code);
+}
+
+ktrcsw(cs)
+ struct ktr_csw *cs;
+{
+ (void)printf("%s %s\n", cs->out ? "stop" : "resume",
+ cs->user ? "user" : "kernel");
+}
+
+ktruser(len, p)
+ int len;
+ unsigned char *p;
+{
+ (void)printf("%d ", len);
+ while (len--)
+ (void)printf(" %02x", *p++);
+ (void)printf("\n");
+
+}
+
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n");
+ exit(1);
+}
--- /dev/null
+set -e
+
+# $FreeBSD: src/usr.bin/kdump/mkioctls,v 1.15.2.3 2001/04/07 11:09:28 ru Exp $
+
+if [ "x$1" = "x-s" ]; then
+ use_switch=1
+ shift
+else
+ use_switch=0
+fi
+
+if [ -z "$1" ]; then
+ echo "usage: sh $0 [-s] include-dir"
+ exit 1
+fi
+
+LC_ALL=C; export LC_ALL
+
+# Build a list of headers that have ioctls in them.
+# XXX should we use an ANSI cpp?
+# XXX netipx conflicts with netns (leave out netns).
+ioctl_includes=`
+ cd $1
+ find * -name '*.h' |
+ egrep -v '^(netns)/' |
+ egrep -v 'if_atm' |
+ egrep -v 'disklabel' |
+ egrep -v 'if_ppp' |
+ egrep -v 'bpf' |
+ egrep -v '^(netiso)/' |
+ egrep -v '^(netccitt)/' |
+ xargs egrep -l \
+'^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO[^a-z0-9_]' |
+ sed -e 's/^/#include </' -e s'/$/>/'
+`
+
+echo "/* XXX obnoxious prerequisites. */"
+echo "#define COMPAT_43 1"
+echo "#include <sys/param.h>"
+echo "#include <sys/socket.h>"
+echo "#include <sys/time.h>"
+echo "#include <sys/tty.h>"
+echo "#include <net/ethernet.h>"
+echo "#include <net/if.h>"
+echo "#include <net/if_var.h>"
+echo "#include <net/route.h>"
+echo "#include <netinet/in.h>"
+echo "#include <netinet/ip_compat.h>"
+echo "#include <netinet/ip_mroute.h>"
+echo "#include <netinet6/in6_var.h>"
+echo "#include <netinet6/nd6.h>"
+echo "#include <netinet6/ip6_mroute.h>"
+echo "#include <netat/appletalk.h>"
+echo "#include <stdio.h>"
+echo ""
+echo "$ioctl_includes"
+echo ""
+
+echo "$ioctl_includes" |
+ cc -no-cpp-precomp -E -I$1 -dM - |
+ awk -v use_switch="$use_switch" '
+BEGIN {
+ print "char *"
+ print "ioctlname(register_t val)"
+ print "{"
+ print ""
+ if (use_switch)
+ print "\tswitch(val) {"
+}
+
+/^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO/ {
+
+ # find where the name starts
+ for (i = 1; i <= NF; i++)
+ if ($i ~ /define/)
+ break;
+ ++i;
+ #
+ if (use_switch)
+ printf("\tcase %s:\n\t\treturn(\"%s\");\n", $i, $i);
+ else
+ printf("\tif (val == %s)\n\t\treturn(\"%s\");\n", $i, $i);
+
+}
+END {
+ if (use_switch)
+ print "\t}"
+ print "\n\treturn(NULL);"
+ print "}"
+}
+'
--- /dev/null
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* Copyright (c) 1992,1995-1999 Apple Computer, Inc. All rights resereved. */
+
+char *syscallnames[] = {
+ "syscall", /* 0 = syscall */
+ "exit", /* 1 = exit */
+ "fork", /* 2 = fork */
+ "read", /* 3 = read */
+ "write", /* 4 = write */
+ "open", /* 5 = open */
+ "close", /* 6 = close */
+ "wait4", /* 7 = wait4 */
+ "obs_creat", /* 8 = old creat */
+ "link", /* 9 = link */
+ "unlink", /* 10 = unlink */
+ "obs_execv", /* 11 = obsolete execv */
+ "chdir", /* 12 = chdir */
+ "fchdir", /* 13 = fchdir */
+ "mknod", /* 14 = mknod */
+ "chmod", /* 15 = chmod */
+ "chown", /* 16 = chown */
+ "obs_break", /* 17 = obsolete break */
+ "obs_getfsstat", /* 18 = obsolete getfsstat */
+ "old_lseek", /* 19 = old lseek */
+ "getpid", /* 20 = getpid */
+ "obs_mount", /* 21 = obsolete mount */
+ "obs_unmount", /* 22 = obsolete unmount */
+ "setuid", /* 23 = setuid */
+ "getuid", /* 24 = getuid */
+ "geteuid", /* 25 = geteuid */
+ "ptrace", /* 26 = ptrace */
+ "recvmsg", /* 27 = recvmsg */
+ "sendmsg", /* 28 = sendmsg */
+ "recvfrom", /* 29 = recvfrom */
+ "accept", /* 30 = accept */
+ "getpeername", /* 31 = getpeername */
+ "getsockname", /* 32 = getsockname */
+ "access", /* 33 = access */
+ "chflags", /* 34 = chflags */
+ "fchflags", /* 35 = fchflags */
+ "sync", /* 36 = sync */
+ "kill", /* 37 = kill */
+ "obs_stat", /* 38 = old stat */
+ "getppid", /* 39 = getppid */
+ "obs_lstat", /* 40 = old lstat */
+ "dup", /* 41 = dup */
+ "pipe", /* 42 = pipe */
+ "getegid", /* 43 = getegid */
+ "profil", /* 44 = profil */
+ "ktrace", /* 45 = ktrace */
+ "sigaction", /* 46 = sigaction */
+ "getgid", /* 47 = getgid */
+ "sigprocmask", /* 48 = sigprocmask */
+ "getlogin", /* 49 = getlogin */
+ "setlogin", /* 50 = setlogin */
+ "acct", /* 51 = acct */
+ "sigpending", /* 52 = sigpending */
+ "sigaltstack", /* 53 = sigaltstack */
+ "ioctl", /* 54 = ioctl */
+ "reboot", /* 55 = reboot */
+ "revoke", /* 56 = revoke */
+ "symlink", /* 57 = symlink */
+ "readlink", /* 58 = readlink */
+ "execve", /* 59 = execve */
+ "umask", /* 60 = umask */
+ "chroot", /* 61 = chroot */
+ "obs_fstat", /* 62 = old fstat */
+ "#63", /* 63 = reserved */
+ "obs_getpagesize", /* 64 = old getpagesize */
+ "msync", /* 65 = msync */
+ "vfork", /* 66 = vfork */
+ "obs_vread", /* 67 = obsolete vread */
+ "obs_vwrite", /* 68 = obsolete vwrite */
+ "sbrk", /* 69 = sbrk */
+ "sstk", /* 70 = sstk */
+ "obs_mmap", /* 71 = old mmap */
+ "obs_vadvise", /* 72 = obsolete vadvise */
+ "munmap", /* 73 = munmap */
+ "mprotect", /* 74 = mprotect */
+ "madvise", /* 75 = madvise */
+ "#76", /* 76 = obsolete vhangup */
+ "#77", /* 77 = obsolete vlimit */
+ "mincore", /* 78 = mincore */
+ "getgroups", /* 79 = getgroups */
+ "setgroups", /* 80 = setgroups */
+ "getpgrp", /* 81 = getpgrp */
+ "setpgid", /* 82 = setpgid */
+ "setitimer", /* 83 = setitimer */
+ "old_wait", /* 84 = old wait */
+ "obs_swapon", /* 85 = swapon */
+ "getitimer", /* 86 = getitimer */
+ "obs_gethostname", /* 87 = old gethostname */
+ "obs_sethostname", /* 88 = old sethostname */
+ "getdtablesize", /* 89 = getdtablesize */
+ "dup2", /* 90 = dup2 */
+ "#91", /* 91 = getdopt */
+ "fcntl", /* 92 = fcntl */
+ "select", /* 93 = select */
+ "#94", /* 94 = setdopt */
+ "fsync", /* 95 = fsync */
+ "setpriority", /* 96 = setpriority */
+ "socket", /* 97 = socket */
+ "connect", /* 98 = connect */
+ "obs_accept", /* 99 = old accept */
+ "getpriority", /* 100 = getpriority */
+ "old_send", /* 101 = old send */
+ "old_recv", /* 102 = old recv */
+ "sigreturn", /* 103 = sigreturn */
+ "bind", /* 104 = bind */
+ "setsockopt", /* 105 = setsockopt */
+ "listen", /* 106 = listen */
+ "#107", /* 107 = obsolete vtimes */
+ "obs_sigvec", /* 108 = old sigvec */
+ "obs_sigblock", /* 109 = old sigblock */
+ "obs_sigsetmask", /* 110 = old sigsetmask */
+ "sigsuspend", /* 111 = sigsuspend */
+ "obs_sigstack", /* 112 = old sigstack */
+ "obs_recvmsg", /* 113 = old recvmsg */
+ "obs_sendmsg", /* 114 = old sendmsg */
+ "#115", /* 115 = obsolete vtrace */
+ "gettimeofday", /* 116 = gettimeofday */
+ "getrusage", /* 117 = getrusage */
+ "getsockopt", /* 118 = getsockopt */
+ "#119", /* 119 = nosys */
+ "readv", /* 120 = readv */
+ "writev", /* 121 = writev */
+ "settimeofday", /* 122 = settimeofday */
+ "fchown", /* 123 = fchown */
+ "fchmod", /* 124 = fchmod */
+ "obs_recvfrom", /* 125 = old recvfrom */
+ "obs_setreuid", /* 126 = old setreuid */
+ "obs_setregid", /* 127 = old setregid */
+ "rename", /* 128 = rename */
+ "obs_truncate", /* 129 = old truncate */
+ "obs_ftruncate", /* 130 = old ftruncate */
+ "flock", /* 131 = flock */
+ "mkfifo", /* 132 = mkfifo */
+ "sendto", /* 133 = sendto */
+ "shutdown", /* 134 = shutdown */
+ "socketpair", /* 135 = socketpair */
+ "mkdir", /* 136 = mkdir */
+ "rmdir", /* 137 = rmdir */
+ "utimes", /* 138 = utimes */
+ "futimes", /* 139 = futimes */
+ "adjtime", /* 140 = adjtime */
+ "obs_getpeername", /* 141 = old getpeername */
+ "obs_gethostid", /* 142 = old gethostid */
+ "#143", /* 143 = old sethostid */
+ "obs_getrlimit", /* 144 = old getrlimit */
+ "obs_setrlimit", /* 145 = old setrlimit */
+ "obs_killpg", /* 146 = old killpg */
+ "setsid", /* 147 = setsid */
+ "#148", /* 148 = obsolete setquota */
+ "#149", /* 149 = obsolete qquota */
+ "obs_getsockname", /* 150 = old getsockname */
+ "#151", /* 151 = nosys */
+ "setprivexec", /* 152 = setprivexec */
+ "pread", /* 153 = pread */
+ "pwrite", /* 154 = pwrite */
+ "nfssvc", /* 155 = nfssvc */
+ "getdirentries", /* 156 =getdirentries */
+ "statfs", /* 157 = statfs */
+ "fstatfs", /* 158 = fstatfs */
+ "unmount", /* 159 = unmount */
+ "#160", /* 160 = obsolete async_daemon */
+ "getfh", /* 161 = getfh */
+ "obs_getdomainname",/* 162 = old getdomainname */
+ "obs_setdomainname",/* 163 = old setdomainname */
+ "#164", /* 164 */
+ "quotactl", /* 165 = quotactl */
+ "#166", /* 166 = obsolete exportfs */
+ "mount", /* 167 = mount */
+ "#168", /* 168 = obsolete ustat */
+ "#169", /* 169 = nosys */
+ "#170", /* 170 = obsolete table */
+ "obs_wait3", /* 171 = old wait3 */
+ "#172", /* 172 = obsolete rpause */
+ "#173", /* 173 = nosys */
+ "#174", /* 174 = obsolete getdents */
+ "#175", /* 175 = nosys */
+ "add_profil", /* 176 = add_profil */ /* NeXT */
+ "#177", /* 177 = nosys */
+ "#178", /* 178 = nosys */
+ "#179", /* 179 = nosys */
+ "kdebug_trace", /* 180 = kdebug_trace */
+ "setgid", /* 181 = setgid */
+ "setegid", /* 182 = setegid */
+ "seteuid", /* 183 = seteuid */
+ "#184", /* 184 = nosys */
+ "#185", /* 185 = nosys */
+ "#186", /* 186 = nosys */
+ "#187", /* 187 = nosys */
+ "stat", /* 188 = stat */
+ "fstat", /* 189 = fstat */
+ "lstat", /* 190 = lstat */
+ "pathconf", /* 191 = pathconf */
+ "fpathconf", /* 192 = fpathconf */
+ "obs_getfsstat", /* 193 = old getfsstat */
+ "getrlimit", /* 194 = getrlimit */
+ "setrlimit", /* 195 = setrlimit */
+ "getdirentries", /* 196 = getdirentries */
+ "mmap", /* 197 = mmap */
+ "#198", /* 198 = __syscall */
+ "lseek", /* 199 = lseek */
+ "truncate", /* 200 = truncate */
+ "ftruncate", /* 201 = ftruncate */
+ "__sysctl", /* 202 = __sysctl */
+ "mlock", /* 203 = mlock */
+ "munlock", /* 204 = munlock */
+ "undelete", /* 205 = undelete */
+ "ATsocket", /* 206 = ATsocket */
+ "ATgetmsg", /* 207 = ATgetmsg */
+ "ATputmsg", /* 208 = ATputmsg */
+ "ATPsndreq", /* 209 = ATPsndreq */
+ "ATPsndrsp", /* 210 = ATPsndrsp */
+ "ATPgetreq", /* 211 = ATPgetreq */
+ "ATPgetrsp", /* 212 = ATPgetrsp */
+ "#213", /* 213 = Reserved for AppleTalk */
+ "#214", /* 214 = Reserved for AppleTalk */
+ "#215", /* 215 = Reserved for AppleTalk */
+ "#216", /* 216 = Reserved */
+ "#217", /* 217 = Reserved */
+ "#218", /* 218 = Reserved */
+ "#219", /* 219 = Reserved */
+ "getattrlist", /* 220 = getattrlist */
+ "setattrlist", /* 221 = setattrlist */
+ "getdirentriesattr", /* 222 = getdirentriesattr */
+ "exchangedata", /* 223 = exchangedata */
+ "checkuseraccess", /* 224 - checkuseraccess */
+ "searchfs", /* 225 = searchfs */
+ "delete", /* 226 = private delete call */
+ "copyfile", /* 227 = copyfile */
+ "#228", /* 228 = nosys */
+ "#229", /* 229 = nosys */
+ "#230", /* 230 = reserved for AFS */
+ "watchevent", /* 231 = watchevent */
+ "waitevent", /* 232 = waitevent */
+ "modwatch", /* 233 = modwatch */
+ "#234", /* 234 = nosys */
+ "#235", /* 235 = nosys */
+ "#236", /* 236 = nosys */
+ "#237", /* 237 = nosys */
+ "#238", /* 238 = nosys */
+ "#239", /* 239 = nosys */
+ "#240", /* 240 = nosys */
+ "#241", /* 241 = nosys */
+ "fsctl", /* 242 = fsctl */
+ "#243", /* 243 = nosys */
+ "#244", /* 244 = nosys */
+ "#245", /* 245 = nosys */
+ "#246", /* 246 = nosys */
+ "#247", /* 247 = nosys */
+ "#248", /* 248 = nosys */
+ "#249", /* 249 = nosys */
+ "minherit", /* 250 = minherit */
+ "semsys", /* 251 = semsys */
+ "msgsys", /* 252 = msgsys */
+ "shmsys", /* 253 = shmsys */
+ "semctl", /* 254 = semctl */
+ "semget", /* 255 = semget */
+ "semop", /* 256 = semop */
+ "semconfig", /* 257 = semconfig */
+ "msgctl", /* 258 = msgctl */
+ "msgget", /* 259 = msgget */
+ "msgsnd", /* 260 = msgsnd */
+ "msgrcv", /* 261 = msgrcv */
+ "shmat", /* 262 = shmat */
+ "shmctl", /* 263 = shmctl */
+ "shmdt", /* 264 = shmdt */
+ "shmget", /* 265 = shmget */
+ "shm_open", /* 266 = shm_open */
+ "shm_unlink", /* 267 = shm_unlink */
+ "sem_open", /* 268 = sem_open */
+ "sem_close", /* 269 = sem_close */
+ "sem_unlink", /* 270 = sem_unlink */
+ "sem_wait", /* 271 = sem_wait */
+ "sem_trywait", /* 272 = sem_trywait */
+ "sem_post", /* 273 = sem_post */
+ "sem_getvalue", /* 274 = sem_getvalue */
+ "sem_init", /* 275 = sem_init */
+ "sem_destroy", /* 276 = sem_destroy */
+ "#277", /* 277 = nosys */
+ "#278", /* 278 = nosys */
+ "#279", /* 279 = nosys */
+ "#280", /* 280 = nosys */
+ "#281", /* 281 = nosys */
+ "#282", /* 282 = nosys */
+ "#283", /* 283 = nosys */
+ "#284", /* 284 = nosys */
+ "#285", /* 285 = nosys */
+ "#286", /* 286 = nosys */
+ "#287", /* 287 = nosys */
+ "#288", /* 288 = nosys */
+ "#289", /* 289 = nosys */
+ "#290", /* 290 = nosys */
+ "#291", /* 291 = nosys */
+ "#292", /* 292 = nosys */
+ "#293", /* 293 = nosys */
+ "#294", /* 294 = nosys */
+ "#295", /* 295 = nosys */
+ "load_shared_file", /* 296 = load_shared_file */
+ "reset_shared_file", /* 297 = reset_shared_file */
+ "new_system_shared_regions", /* 298 = new_system_shared_regions */
+ "#299", /* 299 = nosys */
+ "#300", /* 300 = modnext */
+ "#301", /* 301 = modstat */
+ "#302", /* 302 = modfnext */
+ "#303", /* 303 = modfind */
+ "#304", /* 304 = kldload */
+ "#305", /* 305 = kldunload */
+ "#306", /* 306 = kldfind */
+ "#307", /* 307 = kldnext */
+ "#308", /* 308 = kldstat */
+ "#309", /* 309 = kldfirstmod */
+ "#310", /* 310 = getsid */
+ "#311", /* 311 = setresuid */
+ "#312", /* 312 = setresgid */
+ "#313", /* 313 = obsolete signanosleep */
+ "#314", /* 314 = aio_return */
+ "#315", /* 315 = aio_suspend */
+ "#316", /* 316 = aio_cancel */
+ "#317", /* 317 = aio_error */
+ "#318", /* 318 = aio_read */
+ "#319", /* 319 = aio_write */
+ "#320", /* 320 = lio_listio */
+ "#321", /* 321 = yield */
+ "#322", /* 322 = thr_sleep */
+ "#323", /* 323 = thr_wakeup */
+ "mlockall", /* 324 = mlockall */
+ "munlockall", /* 325 = munlockall */
+ "#326", /* 326 */
+ "issetugid", /* 327 = issetugid */
+ "__pthread_kill", /* 328 = __pthread_kill */
+ "pthread_sigmask", /* 329 = pthread_sigmask */
+ "sigwait", /* 330 = sigwait */
+ "#331", /* 331 */
+ "#332", /* 332 */
+ "#333", /* 333 */
+ "#334", /* 334 */
+ "utrace", /* 335 = utrace */
+ "#336", /* 336 */
+ "#337", /* 337 */
+ "#338", /* 338 */
+ "#339", /* 339 */
+ "#340", /* 340 */
+ "#341", /* 341 */
+ "#342", /* 342 */
+ "#343", /* 343 */
+ "#344", /* 344 */
+ "#345", /* 345 */
+ "#346", /* 346 */
+ "#347", /* 347 */
+ "#348", /* 348 */
+ "#349" /* 349 */
+};
+++ /dev/null
-/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- File: GetSymbolFromPEF.h
-
- Contains: xxx put contents here xxx
-
- Written by: Jeffrey Robbin
-
- Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <2> 9/20/94 TS Dump the globals!
- <1> 9/6/94 TS first checked in
-
-*/
-
-#ifndef __GETSYMBOLFROMPEF__
-#define __GETSYMBOLFROMPEF__
-
-//#include <Types.h>
-
-#pragma options align=mac68k
-
-#define NewPtrSys(a) malloc(a)
-#define DisposePtr(a) free(a)
-
-/*
- Container information
-*/
-
-struct ContainerHeader { /* File/container header layout: */
- unsigned long magicCookie; /* PEF container magic cookie */
- unsigned long containerID; /* 'peff' */
- unsigned long architectureID; /* 'pwpc' | 'm68k' */
- unsigned long versionNumber; /* format version number */
- unsigned long dateTimeStamp; /* date/time stamp (Mac format) */
- unsigned long oldDefVersion; /* old definition version number */
- unsigned long oldImpVersion; /* old implementation version number */
- unsigned long currentVersion; /* current version number */
- short nbrOfSections; /* nbr of sections (rel. 1) */
- short loadableSections; /* nbr of loadable sectionsfor execution */
- /* (= nbr of 1st non-loadable section) */
- LogicalAddress memoryAddress; /* location this container was last loaded */
-};
-typedef struct ContainerHeader ContainerHeader, *ContainerHeaderPtr;
-
-#define kMagic1 'joy!'
-#define kMagic2 'peff'
-
-
-/*
- Section information
-*/
-
-struct SectionHeader { /* Section header layout: */
- long sectionName; /* section name (str tbl container offset) */
- unsigned long sectionAddress; /* preferred base address for the section */
- long execSize; /* execution (byte) size including 0 init) */
- long initSize; /* init (byte) size before 0 init */
- long rawSize; /* raw data size (bytes) */
- long containerOffset; /* container offest to section's raw data */
- unsigned char regionKind; /* section/region classification */
- unsigned char shareKind; /* sharing classification */
- unsigned char alignment; /* log 2 alignment */
- unsigned char reserved; /* <reserved> */
-};
-typedef struct SectionHeader SectionHeader, *SectionHeaderPtr;
-
- /* regionKind section classification: */
- /* loadable sections */
-#define kCodeSection 0U /* code section */
-#define kDataSection 1U /* data section */
-#define kPIDataSection 2U /* "pattern" initialized data */
-#define kConstantSection 3U /* read-only data */
-#define kExecDataSection 6U /* "self modifying" code (!?) */
- /* non-loadable sections */
-#define kLoaderSection 4U /* loader */
-#define kDebugSection 5U /* debugging info */
-#define kExceptionSection 7U /* exception data */
-#define kTracebackSection 8U /* traceback data */
-
-
-/*
- Loader Information
-*/
-
-struct LoaderHeader { /* Loader raw data section header layout: */
- long entrySection; /* entry point section number */
- long entryOffset; /* entry point descr. ldr section offset */
- long initSection; /* init routine section number */
- long initOffset; /* init routine descr. ldr section offset */
- long termSection; /* term routine section number */
- long termOffset; /* term routine descr. ldr section offset */
- long nbrImportIDs; /* nbr of import container id entries */
- long nbrImportSyms; /* nbr of import symbol table entries */
- long nbrRelocSects; /* nbr of relocation sections (headers) */
- long relocsOffset; /* reloc. instructions ldr section offset */
- long strTblOffset; /* string table ldr section offset */
- long slotTblOffset; /* hash slot table ldr section offset */
- long hashSlotTblSz; /* log 2 of nbr of hash slot entries */
- long nbrExportSyms; /* nbr of export symbol table entries */
-};
-typedef struct LoaderHeader LoaderHeader, *LoaderHeaderPtr;
-
-struct LoaderHashSlotEntry { /* Loader export hash slot table entry layout: */
- unsigned long slotEntry; /* chain count (0:13), chain index (14:31) */
-};
-typedef struct LoaderHashSlotEntry LoaderHashSlotEntry, *LoaderHashSlotEntryPtr;
-
-struct LoaderExportChainEntry { /* Loader export hash chain tbl entry layout: */
- union {
- unsigned long _hashWord; /* name length and hash value */
- struct {
- unsigned short _nameLength; /* name length is top half of hash word */
- unsigned short doNotUseThis; /* this field should never be accessed! */
- } _h_h;
- } _h;
-};
-typedef struct LoaderExportChainEntry LoaderExportChainEntry, *LoaderExportChainEntryPtr;
-
-struct ExportSymbolEntry { /* Loader export symbol table entry layout: */
- unsigned long class_and_name; /* symClass (0:7), nameOffset (8:31) */
- long address; /* ldr section offset to exported symbol */
- short sectionNumber; /* section nbr that this export belongs to */
-};
-typedef struct ExportSymbolEntry ExportSymbolEntry, *ExportSymbolEntryPtr;
-
-
-
-/*
- Unpacking Information
-*/
-
- /* "pattern" initialized data opcodes: */
-#define kZero 0U /* zero (clear) bytes */
-#define kBlock 1U /* block transfer bytes */
-#define kRepeat 2U /* repeat block xfer bytes */
-#define kRepeatBlock 3U /* repeat block xfer with contant prefix */
-#define kRepeatZero 4U /* repeat block xfer with contant prefix 0 */
-
-#define kOpcodeShift 0x05U /* shift to access opcode */
-#define kFirstOperandMask 0x1FU /* mask to access 1st operand (count) */
-
-#define PIOP(x) (unsigned char)((x) >> kOpcodeShift) /* extract opcode */
-#define PICNT(x) (long)((x) & kFirstOperandMask) /* extract 1st operand (count) */
-
-/* The following macros are used for extracting count value operands from pidata... */
-
-#define kCountShift 0x07UL /* value shift to concat count bytes */
-#define kCountMask 0x7FUL /* mask to extract count bits from a byte */
-
-#define IS_LAST_PICNT_BYTE(x) (((x) & 0x80U) == 0) /* true if last count byte */
-
-#define CONCAT_PICNT(value, x) (((value)<<kCountShift) | ((x) & kCountMask))
-
-
-
-/*
- Function Prototypes
-*/
-
-static OSStatus GetSymbolFromPEF ( StringPtr theSymbolName,
- LogicalAddress thePEFPtr,
- LogicalAddress theSymbolPtr,
- ByteCount theSymbolSize);
-
-static Boolean SymbolCompare ( StringPtr theLookedForSymbol,
- StringPtr theExportSymbol,
- unsigned long theExportSymbolLength);
-
-static OSErr UnpackPiData (LogicalAddress thePEFPtr,
- SectionHeaderPtr sectionHeaderPtr,
- LogicalAddress * theData);
-
-static unsigned char PEFGetNextByte (unsigned char** rawBuffer, long* rawBufferRemaining);
-
-static unsigned long PEFGetCount(unsigned char** rawBuffer, long* rawBufferRemaining);
-
-
-#pragma options align=reset
-
-#endif
+++ /dev/null
-#define CFRUNLOOP_NEW_API 1
-
-#include "KEXTD.h"
-#include "PTLock.h"
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOKitServer.h>
-#include <IOKit/IOCFSerialize.h>
-#include <IOKit/IOCFURLAccess.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <mach/mach.h>
-#include <mach/mach_host.h>
-#include <mach/bootstrap.h>
-#include <mach/kmod.h>
-#include <syslog.h>
-
-#include <CoreFoundation/CFPriv.h> // for _CFRunLoopSetCurrent();
-
-#define TIMER_PERIOD_S 10
-#define LOOKAPPLENDRV 1
-
-static Boolean gDebug;
-static void KEXTdaemonSignal(void);
-
-// from kernserv/queue.h now kern/queue.h
-
-/*
- * A generic doubly-linked list (queue).
- */
-
-struct queue_entry {
- struct queue_entry *next; /* next element */
- struct queue_entry *prev; /* previous element */
-};
-
-typedef struct queue_entry *queue_t;
-typedef struct queue_entry queue_head_t;
-typedef struct queue_entry queue_chain_t;
-typedef struct queue_entry *queue_entry_t;
-
-/*
- * Macro: queue_init
- * Function:
- * Initialize the given queue.
- * Header:
- * void queue_init(q)
- * queue_t q; \* MODIFIED *\
- */
-#define queue_init(q) ((q)->next = (q)->prev = q)
-
-/*
- * Macro: queue_first
- * Function:
- * Returns the first entry in the queue,
- * Header:
- * queue_entry_t queue_first(q)
- * queue_t q; \* IN *\
- */
-#define queue_first(q) ((q)->next)
-
-/*
- * Macro: queue_next
- * Header:
- * queue_entry_t queue_next(qc)
- * queue_t qc;
- */
-#define queue_next(qc) ((qc)->next)
-
-/*
- * Macro: queue_end
- * Header:
- * boolean_t queue_end(q, qe)
- * queue_t q;
- * queue_entry_t qe;
- */
-#define queue_end(q, qe) ((q) == (qe))
-
-#define queue_empty(q) queue_end((q), queue_first(q))
-
-/*
- * Macro: queue_enter
- * Header:
- * void queue_enter(q, elt, type, field)
- * queue_t q;
- * <type> elt;
- * <type> is what's in our queue
- * <field> is the chain field in (*<type>)
- */
-#define queue_enter(head, elt, type, field) \
-do { \
- if (queue_empty((head))) { \
- (head)->next = (queue_entry_t) elt; \
- (head)->prev = (queue_entry_t) elt; \
- (elt)->field.next = head; \
- (elt)->field.prev = head; \
- } \
- else { \
- register queue_entry_t prev; \
- \
- prev = (head)->prev; \
- (elt)->field.prev = prev; \
- (elt)->field.next = head; \
- (head)->prev = (queue_entry_t)(elt); \
- ((type)prev)->field.next = (queue_entry_t)(elt);\
- } \
-} while(0)
-
-/*
- * Macro: queue_field [internal use only]
- * Function:
- * Find the queue_chain_t (or queue_t) for the
- * given element (thing) in the given queue (head)
- */
-#define queue_field(head, thing, type, field) \
- (((head) == (thing)) ? (head) : &((type)(thing))->field)
-
-/*
- * Macro: queue_remove
- * Header:
- * void queue_remove(q, qe, type, field)
- * arguments as in queue_enter
- */
-#define queue_remove(head, elt, type, field) \
-do { \
- register queue_entry_t next, prev; \
- \
- next = (elt)->field.next; \
- prev = (elt)->field.prev; \
- \
- queue_field((head), next, type, field)->prev = prev; \
- queue_field((head), prev, type, field)->next = next; \
-} while(0)
-
-
-typedef struct _KEXTD {
- CFIndex _refcount;
- CFRunLoopRef _runloop;
- CFRunLoopSourceRef _signalsource;
- CFRunLoopSourceRef _kernelsource;
- CFMutableArrayRef _scanPaths;
- CFMutableArrayRef _unloaded;
- CFMutableArrayRef _helpers;
- queue_head_t _requestQ;
- PTLockRef _runloop_lock;
- PTLockRef _queue_lock;
- KEXTManagerRef _manager;
- mach_port_t _catPort;
- Boolean _initializing;
- Boolean _beVerbose;
-#if TIMERSOURCE
- Boolean _pollFileSystem;
- CFIndex _pollingPeriod;
-#endif
-} KEXTD;
-
-typedef struct _request {
- unsigned int type;
- CFStringRef kmodname;
- CFStringRef kmodvers;
- queue_chain_t link;
-} request_t;
-
-typedef struct _KEXTDHelper {
- void * context;
- KEXTDHelperCallbacks cbs;
-} KEXTDHelper;
-
-CFDictionaryRef _KEXTPersonalityGetProperties(KEXTPersonalityRef personality);
-static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd, CFStringRef parentKey);
-static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd, CFStringRef modName);
-const void * _KEXTPersonalityRetainCB(CFAllocatorRef allocator, const void *ptr);
-void _KEXTPersonalityReleaseCB(CFAllocatorRef allocator, const void *ptr);
-Boolean _KEXTPersonalityEqualCB(const void *ptr1, const void *ptr2);
-mach_port_t _KEXTManagerGetMachPort(KEXTManagerRef manager);
-
-extern kern_return_t
-kmod_control(host_t host,
- kmod_t id,
- kmod_control_flavor_t flavor,
- kmod_args_t *data,
- mach_msg_type_number_t *dataCount);
-
-extern KEXTReturn KERN2KEXTReturn(kern_return_t kr);
-
-static KEXTDRef _kextd = NULL;
-
-static void logErrorFunction(const char * string)
-{
- syslog(LOG_ERR, string);
- return;
-}
-
-static void logMessageFunction(const char * string)
-{
- syslog(LOG_INFO, string);
- return;
-}
-
-
-static void ArrayMergeFunc(const void * val, void * context)
-{
- CFMutableArrayRef array;
-
- array = context;
-
- CFArrayAppendValue(array, val);
-}
-
-static void CFArrayMergeArray(CFMutableArrayRef array1, CFArrayRef array2)
-{
- CFRange range;
-
- if ( !array1 || !array2 ) {
- return;
- }
-
- range = CFRangeMake(0, CFArrayGetCount(array2));
- CFArrayApplyFunction(array2, range, ArrayMergeFunc, array1);
-}
-
-static void CallHelperEvent(void * val, void * context[])
-{
- KEXTDRef kextd;
- KEXTEvent event;
- KEXTDHelper * helper;
- CFTypeRef item;
-
- helper = val;
- kextd = context[0];
- event = *(KEXTEvent *)context[1];
- item = context[2];
-
- if ( helper && context && helper->cbs.EventOccurred ) {
- helper->cbs.EventOccurred(event, item, kextd);
- }
-}
-
-static void ConfigsForBundles(const void * var, void * context[])
-{
- KEXTManagerRef manager;
- KEXTBundleRef bundle;
- CFMutableArrayRef array;
- CFArrayRef configs;
-
- bundle = (KEXTBundleRef)var;
-
- manager = context[0];
- array = context[1];
-
- configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
- if ( configs ) {
- CFArrayMergeArray(array, configs);
- CFRelease(configs);
- }
-}
-
-
-static inline KEXTBootlevel _KEXTDGetBootlevel(KEXTPersonalityRef personality)
-{
- KEXTBootlevel bootlevel;
- CFStringRef priority;
- CFStringRef category;
-
- bootlevel = kKEXTBootlevelExempt;
- priority = KEXTPersonalityGetProperty(personality, CFSTR("BootPriority"));
- if ( !priority ) {
- category = KEXTPersonalityGetProperty(personality, CFSTR("DeviceCategory"));
- if ( !category ) {
- return kKEXTBootlevelExempt;
- }
-
- if ( CFEqual(category, CFSTR("System Controller")) ) {
- bootlevel = kKEXTBootlevelRequired;
- }
- else if ( CFEqual(category, CFSTR("Bus Controller")) ) {
- bootlevel = kKEXTBootlevelFlexible;
- }
- else if ( CFEqual(category, CFSTR("Keyboard")) ) {
- bootlevel = kKEXTBootlevelSingleUser;
- }
- else if ( CFEqual(category, CFSTR("Input Device")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Pointing Device")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Mouse")) ) {
- bootlevel = kKEXTBootlevelRecovery;
- }
- else if ( CFEqual(category, CFSTR("Graphics Controller")) ) {
- bootlevel = kKEXTBootlevelRecovery;
- }
- else if ( CFEqual(category, CFSTR("Graphics Accelerator")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Video Device")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Disk Controller")) ) {
- bootlevel = kKEXTBootlevelFlexible;
- }
- else if ( CFEqual(category, CFSTR("Disk Media")) ) {
- bootlevel = kKEXTBootlevelFlexible;
- }
- else if ( CFEqual(category, CFSTR("Audio Controller")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Sound Device")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(category, CFSTR("Network Controller")) ) {
- bootlevel = kKEXTBootlevelFlexible;
- }
-
- return bootlevel;
- }
-
- if ( CFEqual(priority, CFSTR("Exempt")) ) {
- bootlevel = kKEXTBootlevelExempt;
- }
- else if ( CFEqual(priority, CFSTR("Recovery")) ) {
- bootlevel = kKEXTBootlevelRecovery;
- }
- else if ( CFEqual(priority, CFSTR("Special")) ) {
- bootlevel = kKEXTBootlevelSingleUser;
- }
- else if ( CFEqual(priority, CFSTR("Flexible")) ) {
- bootlevel = kKEXTBootlevelFlexible;
- }
- else if ( CFEqual(priority, CFSTR("Required")) ) {
- bootlevel = kKEXTBootlevelRequired;
- }
-
- return bootlevel;
-}
-
-static void ArrayAddToLoadList(void * val, void * context[])
-{
- KEXTPersonalityRef person;
- KEXTBootlevel bootlevel;
- CFMutableArrayRef unloaded;
- CFMutableArrayRef loadlist;
- CFRange range;
- Boolean doAdd;
-
- if ( !val || !context ) {
- return;
- }
-
- doAdd = true;
- person = val;
- unloaded = context[0];
- loadlist = context[1];
- bootlevel = *(KEXTBootlevel *)context[2];
-
- if ( bootlevel != kKEXTBootlevelNormal ) {
- doAdd = _KEXTDGetBootlevel(person) & bootlevel;
- }
-
- if ( doAdd ) {
- range = CFRangeMake(0, CFArrayGetCount(loadlist));
- if ( !CFArrayContainsValue(loadlist, range, person) ) {
- CFArrayAppendValue(loadlist, person);
- }
- }
- else {
- range = CFRangeMake(0, CFArrayGetCount(unloaded));
- if ( !CFArrayContainsValue(unloaded, range, person) ) {
- CFArrayAppendValue(unloaded, person);
- }
- CFArrayAppendValue(unloaded, person);
- }
-}
-
-static void signalhandler(int signal)
-{
- if ( _kextd && (signal == SIGHUP) ) {
- KEXTDHangup(_kextd);
- }
-}
-
-static KEXTReturn _KEXTDInitSyslog(KEXTD * k)
-{
- openlog("kextd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
-
- return kKEXTReturnSuccess;
-}
-
-// This is called when authenticating a new bundle.
-static KEXTReturn _KEXTDAuthenticateBundleCB(CFURLRef url, void * context)
-{
- Boolean ret;
-
- ret = KEXTManagerAuthenticateURL(url);
- if ( !ret ) {
- KEXTD * k = (KEXTD *)context;
- KEXTEvent event;
- CFStringRef urlString;
- CFRange range;
- char name[256];
- void * context2[3];
-
- urlString = CFURLGetString(url);
- if ( CFStringGetCString(urlString, name, 256, kCFStringEncodingNonLossyASCII) )
- syslog(LOG_ERR, "%s failed authentication.", name);
-
- event = kKEXTEventBundleAuthenticationFailed;
- context2[0] = k;
- context2[1] = &event;
- context2[2] = (void *)url;
-
- range = CFRangeMake(0, CFArrayGetCount(k->_helpers));
- CFArrayApplyFunction(k->_helpers, range, (CFArrayApplierFunction)CallHelperEvent, context2);
- }
-
- return ret;
-}
-
-// This is called when a new bundle has been found.
-static Boolean _KEXTDWillAddBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
-{
- KEXTD * k = (KEXTD *)context;
- CFURLRef url;
- CFIndex count;
- CFIndex i;
- Boolean ret;
-
- ret = true;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.BundleAdd ) {
- ret = helper->cbs.BundleAdd(bundle, helper->context);
- if ( !ret )
- break;
- }
- }
-
- url = KEXTBundleCopyURL(bundle);
- if ( url ) {
- if ( k->_beVerbose && ret ) {
- CFStringRef cfstr;
- char str[256];
-
- cfstr = CFURLGetString(url);
- if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
- syslog(LOG_INFO, "%s added.", str);
- }
- }
-
- // Remove any unloaded personalities from look-aside queue
- // which are in this bundle.
- _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef)k, KEXTBundleGetPrimaryKey(bundle));
- CFRelease(url);
- }
-
- return ret;
-}
-
-// This is called after a bundle has been added to the KEXTManager database.
-static void _KEXTDWasAddedBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
-{
- KEXTD * k;
- KEXTBootlevel bootlevel;
- CFMutableArrayRef toload;
- CFArrayRef persons;
- CFArrayRef configs;
- CFArrayRef unloaded;
- CFRange range;
- void * context2[3];
-
- k = (KEXTD *)context;
- if ( k->_initializing ) {
- return;
- }
-
- bootlevel = kKEXTBootlevelNormal;
-
- toload = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if ( !toload ) {
- return;
- }
-
- context2[0] = k->_unloaded;
- context2[1] = toload;
- context2[2] = &bootlevel;
-
-
- // Create a list of all personalities and configurations
- // and send it to the catalogue. First, get the unloaded
- // personalities.
- unloaded = CFArrayCreateCopy(kCFAllocatorDefault, k->_unloaded);
- CFArrayRemoveAllValues(k->_unloaded);
- if ( unloaded ) {
- range = CFRangeMake(0, CFArrayGetCount(unloaded));
- CFArrayApplyFunction(unloaded, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
- CFRelease(unloaded);
- }
-
- persons = KEXTManagerCopyPersonalitiesForBundle(manager, bundle);
- if ( persons ) {
- range = CFRangeMake(0, CFArrayGetCount(persons));
- CFArrayApplyFunction(persons, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
- CFRelease(persons);
- }
-
- configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
- if ( configs ) {
- range = CFRangeMake(0, CFArrayGetCount(configs));
- CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
- CFRelease(configs);
-
- }
-
- // Send the list to IOCatalogue.
- if ( CFArrayGetCount(toload) > 0 ) {
- KEXTManagerLoadPersonalities(k->_manager, toload);
- }
-
- CFRelease(toload);
-}
-
-static void _KEXTDConfigWasAdded(KEXTManagerRef manager, KEXTConfigRef config, void * context)
-{
- KEXTD * kextd;
-
- if ( !manager || !config || !context ) {
- return;
- }
-
- kextd = context;
-
- if ( !kextd->_initializing ) {
- CFStringRef primaryKey;
- CFArrayRef array;
- void * vals[1];
-
- primaryKey = CFDictionaryGetValue(config, CFSTR("ParentKey"));
- if ( !primaryKey ) {
- return;
- }
-
- if ( !KEXTManagerGetBundle(manager, primaryKey) ) {
- return;
- }
-
- vals[0] = config;
- array = CFArrayCreate(kCFAllocatorDefault, vals, 1, &kCFTypeArrayCallBacks);
- if ( array ) {
- KEXTManagerLoadPersonalities(manager, array);
- CFRelease(array);
- }
- }
-}
-
-static void _KEXTDConfigWasRemoved(KEXTManagerRef manager, KEXTConfigRef config, void * context)
-{
- KEXTD * kextd;
-
- if ( !manager || !config || !context ) {
- return;
- }
-
- kextd = context;
-
- if ( !kextd->_initializing ) {
- KEXTManagerUnloadPersonality(manager, config);
- }
-}
-
-static void ArrayUnloadPersonality(const void * val, void * context)
-{
- KEXTManagerRef manager;
- KEXTPersonalityRef person;
-
- manager = context;
- person = (KEXTPersonalityRef)val;
-
- KEXTManagerUnloadPersonality(manager, person);
-}
-
-// This is called when a bundle has been removed from the filesystem.
-static Boolean _KEXTDWillRemoveBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
-{
- KEXTD * k = (KEXTD *)context;
- CFIndex count;
- CFIndex i;
- Boolean ret;
-
- ret = true;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.BundleRemove ) {
- ret = helper->cbs.BundleRemove(bundle, helper->context);
- if ( !ret )
- break;
- }
- }
-
- if ( ret ) {
- CFArrayRef personalities;
- CFArrayRef configs;
- CFURLRef url;
- CFRange range;
-
- // XXX -- svail: might want to unload bundle personalities
- // from IOCatalogue and maybe unload the modules if possible.
- // If a module is present with active personalities, don't remove
- // bundle from database.
- personalities = KEXTManagerCopyPersonalitiesForBundle(manager, bundle);
- if ( personalities ) {
- range = CFRangeMake(0, CFArrayGetCount(personalities));
- CFArrayApplyFunction(personalities, range, ArrayUnloadPersonality, manager);
- CFRelease(personalities);
- }
-
- configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
- if ( configs ) {
- range = CFRangeMake(0, CFArrayGetCount(configs));
- CFArrayApplyFunction(configs, range, ArrayUnloadPersonality, manager);
- CFRelease(configs);
- }
-
- url = KEXTBundleCopyURL(bundle);
- if ( url ) {
- if ( k->_beVerbose && ret ) {
- CFStringRef cfstr;
- char str[256];
-
- cfstr = CFURLGetString(url);
- if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
- syslog(LOG_INFO, "%s removed.", str);
- }
- }
-
- // Remove any unloaded personalities from the unloaded
- // list if they are associated with the bundle.
-
- _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef)k, KEXTBundleGetPrimaryKey(bundle));
- CFRelease(url);
- }
- }
-
- return ret;
-}
-
-// This is called before KEXT loads a KMOD.
-static Boolean _KEXTDModuleWillLoadCB(KEXTManagerRef manager, KEXTModuleRef module, void * context)
-{
- KEXTD * k;
- CFIndex count;
- CFIndex i;
- Boolean ret;
-
- k = (KEXTD *)context;
-
- ret = true;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.ModuleWillLoad ) {
- if ( !helper->cbs.ModuleWillLoad(module, helper->context) ) {
- ret = false;
- break;
- }
- }
- }
-
- if ( ret ) {
- CFStringRef moduleName;
- char name[256];
-
- moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
- if ( !moduleName )
- return false;
-
- if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
- return false;
-
- syslog(LOG_INFO, "loading module: %s.\n", name);
- }
-
- return ret;
-}
-
-// This is called when a module has been successfully loaded.
-static void _KEXTDModuleWasLoadedCB(KEXTManagerRef manager, KEXTModuleRef module, void * context)
-{
- KEXTD * k;
- CFArrayRef array;
- CFMutableArrayRef send;
- CFIndex count;
- CFIndex i;
-
- k = (KEXTD *)context;
-
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.ModuleWasLoaded ) {
- helper->cbs.ModuleWasLoaded(module, helper->context);
- }
- }
-
- // Remove personalities from unloaded list if they
- // are associated with the module and pass them to the
- // kernel just in case they aren't there yet.
-
- array = CFArrayCreateCopy(kCFAllocatorDefault, k->_unloaded);
- send = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- count = CFArrayGetCount(array);
-
- CFArrayRemoveAllValues(k->_unloaded);
-
- for ( i = 0; i < count; i++ ) {
- KEXTPersonalityRef person;
- CFStringRef moduleID;
- CFStringRef personalityBundleID;
-
- person = (KEXTPersonalityRef)CFArrayGetValueAtIndex(array, i);
- if ( !person ) {
- continue;
- }
-
- moduleID = KEXTPersonalityGetProperty(person, CFSTR("CFBundleIdentifier"));
- if ( !moduleID ) {
- continue;
- }
-
- personalityBundleID = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
- if ( !personalityBundleID ) {
- continue;
- }
-
- if ( !CFEqual(moduleID, personalityBundleID) ) {
- CFArrayAppendValue(k->_unloaded, person);
- }
- else {
- CFArrayAppendValue(send, person);
- }
- }
-
- if ( CFArrayGetCount(send) > 0 ) {
- KEXTManagerLoadPersonalities(k->_manager, send);
- }
-
- CFRelease(send);
- CFRelease(array);
-
- if ( k->_beVerbose ) {
- CFStringRef moduleName;
- char name[256];
-
- moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
- if ( !moduleName )
- return;
-
- if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
- return;
-
- syslog(LOG_INFO, "loaded module: %s\n", name);
- }
-}
-
-static KEXTReturn _KEXTDModuleErrorCB(KEXTManagerRef manager, KEXTModuleRef module, KEXTReturn error, void * context)
-{
- char name[256];
- KEXTD * k;
- KEXTReturn ret;
- CFIndex i;
- CFIndex count;
- CFStringRef moduleName;
-
- k = (KEXTD *)context;
-
- moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
- if ( !moduleName )
- return kKEXTReturnPropertyNotFound;
-
- if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
- return kKEXTReturnNoMemory;
-
- if ( error == kKEXTReturnModuleAlreadyLoaded ) {
- if ( k->_beVerbose )
- syslog(LOG_INFO, "module already loaded: %s.\n", name);
-
- return error;
- }
-
- ret = error;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.ModuleLoadError ) {
- ret = helper->cbs.ModuleLoadError(module, error, helper->context);
- if ( ret == kKEXTReturnSuccess ) {
- break;
- }
- }
- }
- if ( ret == kKEXTReturnSuccess )
- return kKEXTReturnSuccess;
-
- syslog(LOG_ERR, "error (%d) loading module: %s.\n", ret, name);
-
- return ret;
-}
-
-#if TIMERSOURCE
-static void _KEXTDTimerCallout(CFRunLoopTimerRef timer, void * info)
-{
- KEXTDScanPaths((KEXTDRef)info, false);
-}
-#endif
-
-static void _KEXTDSIGHUPCallout(void * info)
-{
- KEXTD * k;
-
- k = (KEXTD *)info;
- if ( k->_beVerbose ) {
- syslog(LOG_INFO, "user requests directory re-scan.");
- }
-
- // Check for new or removed bundles and do the appropriate
- // things.
- KEXTDScanPaths((KEXTDRef)info, false);
-
- // Make sure we try to load the unloaded personalities
- // It's probably overkill to do this here.
- if ( CFArrayGetCount(k->_unloaded) > 0 ) {
- KEXTManagerLoadPersonalities(k->_manager, k->_unloaded);
- }
-}
-
-// This function is called when IOCatalogue requests a driver module.
-static void _KEXTDPerform(void * info)
-{
- KEXTD * k;
- unsigned int type;
-
- k = (KEXTD *)info;
-
-// KEXTDScanPaths((KEXTDRef)k, false);
-
- PTLockTakeLock(k->_queue_lock);
- while ( !queue_empty(&k->_requestQ) ) {
- request_t * reqstruct;
- CFStringRef name;
-
- // Dequeue the kernel request structure.
- reqstruct = (request_t *)queue_first(&k->_requestQ);
- queue_remove(&k->_requestQ, reqstruct, request_t *, link);
- PTLockUnlock(k->_queue_lock);
-
- type = reqstruct->type;
- name = reqstruct->kmodname;
- free(reqstruct);
-
- if ( name ) {
-
- if ( k->_beVerbose ) {
- char modname[256];
-
- if ( CFStringGetCString(name, modname, 256, kCFStringEncodingNonLossyASCII) ) {
- syslog(LOG_INFO, "kernel requests module: %s", modname);
- }
- }
-
- KEXTDKernelRequest((KEXTDRef)k, name);
- CFRelease(name);
- }
-
- PTLockTakeLock(k->_queue_lock);
- }
- PTLockUnlock(k->_queue_lock);
-}
-
-KEXTDRef KEXTDCreate(CFArrayRef scanPaths, KEXTReturn * error)
-{
- KEXTD * kextd;
-
- kextd = (KEXTD *)malloc(sizeof(KEXTD));
- if ( !kextd ) {
- *error = kKEXTReturnNoMemory;
- return NULL;
- }
- memset(kextd, 0, sizeof(KEXTD));
-
- kextd->_queue_lock = PTLockCreate();
- kextd->_runloop_lock = PTLockCreate();
-
- kextd->_helpers = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
- kextd->_unloaded = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- kextd->_scanPaths = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if ( !kextd->_scanPaths || !kextd->_unloaded || !kextd->_helpers ) {
- *error = kKEXTReturnNoMemory;
- KEXTDFree((KEXTDRef)kextd);
- return NULL;
- }
-
- kextd->_initializing = true;
- kextd->_beVerbose = false;
-#if TIMERSOURCE
- kextd->_pollFileSystem = false;
- kextd->_pollingPeriod = TIMER_PERIOD_S;
-#endif
-
- queue_init(&kextd->_requestQ);
-
- if ( scanPaths ) {
- CFURLRef url;
- CFIndex count;
- CFIndex i;
-
- count = CFArrayGetCount(scanPaths);
- for ( i = 0; i < count; i++ ) {
- url = (CFURLRef)CFArrayGetValueAtIndex(scanPaths, i);
- KEXTDAddScanPath((KEXTDRef)kextd, url);
- }
- }
-
- return (KEXTDRef)kextd;
-}
-
-static void _KEXTDFlushHelpers(KEXTDRef kextd)
-{
- KEXTD * k;
- CFIndex count;
- CFIndex i;
-
- k = (KEXTD *)kextd;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.DaemonWillTerminate )
- helper->cbs.DaemonWillTerminate(helper->context);
- if ( helper->cbs.HelperFinalize )
- helper->cbs.HelperFinalize(helper->context);
-
- free(helper);
- }
-}
-
-void KEXTDFree(KEXTDRef kextd)
-{
- KEXTD * k;
-
- k = (KEXTD *)kextd;
-
- syslog(LOG_DEBUG, "terminating.");
-
- if ( k->_helpers ) {
- _KEXTDFlushHelpers(kextd);
- CFRelease(k->_helpers);
- }
- if ( k->_kernelsource )
- CFRelease(k->_kernelsource);
- if ( k->_signalsource )
- CFRelease(k->_signalsource);
- if ( k->_runloop )
- CFRelease(k->_runloop);
- if ( k->_scanPaths )
- CFRelease(k->_scanPaths);
- if ( k->_manager )
- KEXTManagerRelease(k->_manager);
- if ( k->_queue_lock )
- PTLockFree(k->_queue_lock);
- if ( k->_runloop_lock )
- PTLockFree(k->_runloop_lock);
-
- closelog();
-
- free(kextd);
-}
-
-void KEXTDReset(KEXTDRef kextd)
-{
- KEXTD * k;
- CFIndex count;
- CFIndex i;
-
- syslog(LOG_DEBUG, "resetting.");
-
- k = (KEXTD *)kextd;
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.EventOccurred )
- helper->cbs.EventOccurred(kKEXTEventReset, NULL, helper->context);
- }
-
- if ( k->_manager )
- KEXTManagerReset(k->_manager);
-
- KEXTDScanPaths(kextd, false);
-}
-
-static KEXTReturn _KEXTDSendDataToCatalog(KEXTDRef kextd, int flag, CFTypeRef obj)
-{
- KEXTD * k;
- KEXTReturn error;
- CFDataRef data;
- CFIndex len;
- void * ptr;
-
- k = (KEXTD *)kextd;
- data = NULL;
- error = kKEXTReturnSuccess;
-
- data = IOCFSerialize(obj, 0);
- if ( !data ) {
- return kKEXTReturnSerializationError;
- }
-
- len = CFDataGetLength(data);
- ptr = (void *)CFDataGetBytePtr(data);
- error = KERN2KEXTReturn(IOCatalogueSendData(k->_catPort, flag, ptr, len));
- CFRelease(data);
-
- return error;
-}
-
-static KEXTReturn _KEXTDSendPersonalities(KEXTDRef kextd, KEXTBootlevel bootlevel)
-{
- KEXTReturn error;
- CFArrayRef persons;
- CFArrayRef bundles;
- CFMutableArrayRef configs;
- CFMutableArrayRef toload;
- CFRange range;
- void * context[3];
-
- error = kKEXTReturnSuccess;
-
- toload = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if ( !toload ) {
- return kKEXTReturnNoMemory;
- }
-
- configs = NULL;
- bundles = KEXTManagerCopyAllBundles(((KEXTD*)kextd)->_manager);
- if ( bundles ) {
- configs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if ( !configs ) {
- CFRelease(bundles);
- CFRelease(toload);
- return kKEXTReturnNoMemory;
- }
-
- context[0] = ((KEXTD*)kextd)->_manager;
- context[1] = configs;
-
- range = CFRangeMake(0, CFArrayGetCount(bundles));
- CFArrayApplyFunction(bundles, range, (CFArrayApplierFunction)ConfigsForBundles, context);
- CFRelease(bundles);
- }
-
- // Filter out any inappropriate personalities given the bootlevel of the
- // system. Store these personalities in the _unloaded list, they will be
- // loaded when a SIGHUP is sent to the daemon.
- context[0] = ((KEXTD *)kextd)->_unloaded;
- context[1] = toload;
- context[2] = &bootlevel;
-
- persons = KEXTManagerCopyAllPersonalities(((KEXTD*)kextd)->_manager);
- if ( persons ) {
- range = CFRangeMake(0, CFArrayGetCount(persons));
- CFArrayApplyFunction(persons, range, (CFArrayApplierFunction)ArrayAddToLoadList, context);
- CFRelease(persons);
- }
-
- if ( configs ) {
- range = CFRangeMake(0, CFArrayGetCount(configs));
- CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)ArrayAddToLoadList, context);
- CFRelease(configs);
- }
-
- if ( CFArrayGetCount(toload) > 0 ) {
- error = KEXTManagerLoadPersonalities(((KEXTD *)kextd)->_manager, toload);
- }
-
- KEXTdaemonSignal();
-
- CFRelease(toload);
-
- return error;
-
-}
-
-static inline Boolean _KEXTPersonalityNeedsModule(KEXTPersonalityRef person, CFStringRef modName)
-{
- CFStringRef name;
-
- name = KEXTPersonalityGetProperty(person, CFSTR("CFBundleIdentifier"));
- if ( !name ) {
- return false;
- }
-
- return CFEqual(name, modName);
-}
-
-// If a module fails to load for some reason, then put the
-// personalities associated with this module in a look-aside
-// buffer, we'll try loading them later, maybe when a broken
-// dependency is fixed.
-static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd, CFStringRef modName)
-{
- CFArrayRef array;
- CFIndex i;
- CFIndex count;
- KEXTD * k;
-
- if ( !modName )
- return;
-
- k = (KEXTD *)kextd;
-
- array = KEXTManagerCopyAllEntities(k->_manager);
- if ( !array )
- return;
-
- // Find personalities which depend on this module.
- count = CFArrayGetCount(array);
- for ( i = 0; i < count; i++ ) {
- CFStringRef type;
- CFStringRef name;
- CFRange range;
- KEXTEntityRef entity;
-
- entity = (KEXTEntityRef)CFArrayGetValueAtIndex(array, i);
- if ( !entity )
- continue;
-
- type = KEXTManagerGetEntityType(entity);
- if ( !type || !CFEqual(type, KEXTPersonalityGetEntityType()) ) {
- continue;
- }
-
- name = KEXTPersonalityGetProperty(entity, CFSTR("CFBundleIdentifier"));
- if ( !name || !CFEqual(modName, name) ) {
- continue;
- }
-
- range = CFRangeMake(0, CFArrayGetCount(k->_unloaded));
-
- if ( CFArrayContainsValue(k->_unloaded, range, entity) ) {
- continue;
- }
-
- CFArrayAppendValue(k->_unloaded, entity);
-
- if ( !k->_initializing ) {
- KEXTManagerUnloadPersonality(k->_manager, entity);
- }
-
- }
- CFRelease(array);
-}
-
-static void RemovePersonsWithParentFromUnloadedList(void * val, void * context[])
-{
- KEXTPersonalityRef person;
- CFMutableArrayRef unloaded;
- CFStringRef parentKey;
- CFStringRef key;
-
- if ( !val || !context ) {
- return;
- }
-
- person = val;
- unloaded = context[0];
- parentKey = context[1];
-
- key = CFDictionaryGetValue(person, CFSTR("ParentKey"));
- if ( !parentKey || !key || CFEqual(parentKey, key) ) {
- return;
- }
-
- CFArrayAppendValue(unloaded, person);
-}
-
-// Remove personalities from the unloaded list if their
-// associated bundle is removed.
-static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd, CFStringRef parentKey)
-{
- CFMutableArrayRef unloaded;
- CFArrayRef array;
- CFRange range;
- void * context[2];
-
- unloaded = ((KEXTD *)kextd)->_unloaded;
-
- array = CFArrayCreateCopy(kCFAllocatorDefault, unloaded);
- CFArrayRemoveAllValues(unloaded);
-
- context[0] = unloaded;
- context[1] = (void *)parentKey;
-
- range = CFRangeMake(0, CFArrayGetCount(array));
- CFArrayApplyFunction(
- array,
- range,
- (CFArrayApplierFunction)RemovePersonsWithParentFromUnloadedList,
- context);
-
- CFRelease(array);
-}
-
-static KEXTReturn _KEXTDProcessLoadCommand(KEXTDRef kextd, CFStringRef name)
-{
- char cname[256];
- KEXTReturn error;
- KEXTD * k;
-
- k = (KEXTD *)kextd;
- if ( !CFStringGetCString(name, cname, 256, kCFStringEncodingNonLossyASCII) ) {
- error = kKEXTReturnNoMemory;
- return error;
- }
-
- error = KEXTDLoadModule(kextd, name);
- if ( error != kKEXTReturnSuccess &&
- error != kKEXTReturnModuleAlreadyLoaded ) {
- CFDictionaryRef matchingDict;
- const void * keys[1];
- const void * vals[1];
-
- do {
- keys[0] = CFSTR("CFBundleIdentifier");
- vals[0] = name;
-
- if ( !vals[0] ) {
- error = kKEXTReturnPropertyNotFound;
- break;
- }
-
- matchingDict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if ( !matchingDict ) {
- error = kKEXTReturnNoMemory;
- break;
- }
-
- error = _KEXTDSendDataToCatalog(kextd, kIOCatalogRemoveDrivers, matchingDict);
- CFRelease(matchingDict);
- if ( error != kKEXTReturnSuccess ) {
- syslog(LOG_DEBUG, "error ( %d) removing drivers.", error);
- break;
- }
- } while ( false );
-
- // Place personalities which failed to load this module onto
- // a look-aside queue. We'll try to load the module later
- // when a broken dependency is fixed.
- _KEXTDAddPersonalitiesWithModuleToUnloadedList(kextd, name);
- }
- else {
-
- error = KERN2KEXTReturn(IOCatalogueModuleLoaded(k->_catPort, cname));
- if ( error != kKEXTReturnSuccess ) {
- syslog(LOG_DEBUG, "error (%d) signalling IOCatalogue.", error);
- }
- }
-
- return error;
-}
-
-void KEXTDHangup(KEXTDRef kextd)
-{
- KEXTD * k;
-
- k = (KEXTD *)kextd;
- if ( k->_signalsource ) {
- PTLockTakeLock(k->_runloop_lock);
- CFRunLoopSourceSignal(k->_signalsource);
- CFRunLoopWakeUp(k->_runloop);
- PTLockUnlock(k->_runloop_lock);
- }
-}
-
-KEXTReturn KEXTDKernelRequest(KEXTDRef kextd, CFStringRef name)
-{
- KEXTD * k;
- KEXTReturn ret;
-
- k = (KEXTD *)kextd;
- ret = kKEXTReturnBadArgument;
- if ( name ) {
- KEXTEvent event;
- CFRange range;
- void * context[3];
-
- event = kKEXTEventModuleRequest;
-
- context[0] = kextd;
- context[1] = &event;
- context[2] = (void *)name;
-
- range = CFRangeMake(0, CFArrayGetCount(k->_helpers));
- CFArrayApplyFunction(k->_helpers, range, (CFArrayApplierFunction)CallHelperEvent, context);
- ret = _KEXTDProcessLoadCommand((KEXTDRef)k, name);
- }
-
- return ret;
-}
-
-// The kernel blocks the thread which entered this
-// function until the kernel requests a driver to load.
-static void * _KEXTDKmodWait(void * info)
-{
- mach_port_t kmodPort;
- KEXTD * kextd;
- KEXTReturn error;
- request_t * reqstruct;
- CFStringRef str;
- unsigned int type;
-
- if ( !info )
- return (void *)kKEXTReturnBadArgument;
-
- kmodPort = mach_host_self(); /* must be privileged to work */
-
- kextd = (KEXTD *)info;
- if ( !kextd->_kernelsource )
- return (void *)kKEXTReturnBadArgument;
-
- while ( 1 ) {
- kmod_args_t data;
- kmod_load_extension_cmd_t * cmd;
- mach_msg_type_number_t dataCount;
- kern_return_t kr;
-
- data = 0;
- dataCount = 0;
- error = kKEXTReturnSuccess;
-
- // Wait for kernel to unblock the thread.
- kr = kmod_control(kmodPort, 0, KMOD_CNTL_GET_CMD, &data, &dataCount);
- if ( kr != KERN_SUCCESS ) {
- syslog(LOG_ERR, "error (%d): kmod_control.\n", kr);
- continue;
- }
-
- cmd = (kmod_load_extension_cmd_t *)data;
- type = cmd->type;
- str = 0;
-
- switch ( type ) {
-
- case kIOCatalogMatchIdle:
- break;
-
- case KMOD_LOAD_EXTENSION_PACKET: {
-
- str = CFStringCreateWithCString(NULL, cmd->name, kCFStringEncodingNonLossyASCII);
- if( str)
- break;
- // else fall thru
- }
- default:
- error = kKEXTReturnError;
- break;
- }
-
- if( error == kKEXTReturnSuccess) {
-
- reqstruct = (request_t *)malloc(sizeof(request_t));
- if( reqstruct) {
- memset(reqstruct, 0, sizeof(request_t));
- reqstruct->type = cmd->type;
- reqstruct->kmodname = str;
- // queue up a reqest.
- PTLockTakeLock(kextd->_queue_lock);
- queue_enter(&kextd->_requestQ, reqstruct, request_t *, link);
- PTLockUnlock(kextd->_queue_lock);
-
- // wake up the runloop.
- PTLockTakeLock(kextd->_runloop_lock);
- CFRunLoopSourceSignal(kextd->_kernelsource);
- CFRunLoopWakeUp(kextd->_runloop);
- PTLockUnlock(kextd->_runloop_lock);
- }
- }
-
- // Deallocate kernel allocated memory.
- vm_deallocate(mach_task_self(), (vm_address_t)data, dataCount);
- if ( kr != KERN_SUCCESS ) {
- syslog(LOG_DEBUG, "vm_deallocate failed. aborting.\n");
- exit(1);
- }
- }
-
- return (void *)kKEXTReturnSuccess;
-}
-
-
-#include <fcntl.h>
-#include <paths.h>
-#include <unistd.h>
-#include <assert.h>
-#include <mach/semaphore.h>
-#include <mach/sync_policy.h>
-#include <mach/bootstrap.h> /* bootstrap_ports */
-#undef _bootstrap_user_ /* XXX FIXME */
-#include <servers/bootstrap.h> /* bootstrap_look_up */
-#include <servers/bootstrap_defs.h>
-
-static void
-KEXTdaemonSignal(void)
-{
- kern_return_t kr;
- mach_port_t bs_port;
- semaphore_t sema;
- static boolean_t signalled = false;
-
- if (signalled)
- return;
- signalled = TRUE;
- if (gDebug) {
- printf("kextd: signal\n");
- return;
- }
-
- kr = task_get_bootstrap_port(mach_task_self(), &bs_port);
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "task_get_bootstrap_port (%lx)\n", kr);
- kr = bootstrap_look_up(bs_port, "kextdsignal", &sema);
- if( kr != BOOTSTRAP_SUCCESS )
- syslog(LOG_ERR, "bootstrap_look_up(%lx)\n", kr);
- kr = semaphore_signal_all( sema );
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "semaphore_signal_all(%lx)\n", kr);
-
-}
-
-static semaphore_t gDaemonSema;
-
-static void
-KEXTdaemonWait(void)
-{
- kern_return_t kr;
- mach_port_t masterPort;
- mach_timespec_t waitTime = { 40, 0 };
-
- kr = semaphore_timedwait( gDaemonSema, waitTime );
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "semaphore_timedwait(%lx)\n", kr);
-
- IOMasterPort( MACH_PORT_NULL, &masterPort );
- IOKitWaitQuiet( masterPort, &waitTime );
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "IOKitWaitQuiet(%lx)\n", kr);
-}
-
-static int
-KEXTdaemon(nochdir, noclose)
- int nochdir, noclose;
-{
- kern_return_t kr;
- mach_port_t bs_port;
- int fd;
-
- kr = semaphore_create( mach_task_self(), &gDaemonSema, SYNC_POLICY_FIFO, 0);
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "semaphore_create(%lx)\n", kr);
- kr = task_get_bootstrap_port(mach_task_self(), &bs_port);
- if( kr != KERN_SUCCESS )
- syslog(LOG_ERR, "task_get_bootstrap_port(%lx)\n", kr);
- kr = bootstrap_register(bs_port, "kextdsignal", gDaemonSema);
- if( kr != BOOTSTRAP_SUCCESS )
- syslog(LOG_ERR, "bootstrap_look_up(%lx)\n", kr);
-
- switch (fork()) {
- case -1:
- return (-1);
- case 0:
- /*
- * Under some circumstances a CFRunLoop could have been established
- * in the parent process. Since the mach ports associated with the
- * run loop are not passed to the child process we need to start
- * with a clean slate.
- */
- _CFRunLoopSetCurrent(NULL);
-
- break;
- default:
- KEXTdaemonWait();
- _exit(0);
- }
-
- if (setsid() == -1)
- return (-1);
-
- if (!nochdir)
- (void)chdir("/");
-
- if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
- (void)dup2(fd, STDIN_FILENO);
- (void)dup2(fd, STDOUT_FILENO);
- (void)dup2(fd, STDERR_FILENO);
- if (fd > 2)
- (void)close (fd);
- }
- return (0);
-}
-
-
-#if TIMERSOURCE
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel, Boolean cdMKextBoot)
-#else
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel, Boolean cdMKextBoot)
-#endif
-{
- pthread_attr_t kmod_thread_attr;
- pthread_t kmod_thread;
- KEXTReturn error;
- KEXTD * k;
- CFIndex count;
- CFIndex i;
- CFRunLoopSourceContext sourceContext;
- KEXTManagerBundleLoadingCallbacks bcb = {
- 0,
- _KEXTDAuthenticateBundleCB,
- _KEXTDWillAddBundleCB,
- _KEXTDWasAddedBundleCB,
- NULL,
- _KEXTDWillRemoveBundleCB,
- NULL,
- };
- KEXTManagerModuleLoadingCallbacks modcbs = {
- 0,
- _KEXTDModuleWillLoadCB,
- _KEXTDModuleWasLoadedCB,
- _KEXTDModuleErrorCB,
- NULL,
- NULL,
- };
- KEXTManagerConfigsCallbacks cfgcbs = {
- 0,
- NULL,
- _KEXTDConfigWasAdded,
- NULL,
- _KEXTDConfigWasRemoved,
- };
-
- gDebug = debug;
- if (!debug && !cdMKextBoot) {
- errno = 0;
- KEXTdaemon(0, 0);
- if ( errno ) {
- syslog(LOG_ERR, "failed to daemonize process. Aborting!\n");
- return kKEXTReturnError;
- }
- }
-
- k = (KEXTD *)kextd;
- k->_manager = KEXTManagerCreate(&bcb, &modcbs, NULL, &cfgcbs, kextd,
- &logErrorFunction, &logMessageFunction, safeBoot, &error);
- if ( !k->_manager )
- return error;
-
- k->_initializing = true;
- k->_catPort = _KEXTManagerGetMachPort(k->_manager);
- k->_beVerbose = beVerbose;
-#if TIMERSOURCE
- k->_pollFileSystem = poll;
- k->_pollingPeriod = period;
-#endif
- memset(&sourceContext, NULL, sizeof(CFRunLoopSourceContext));
-
- error = _KEXTDInitSyslog(k);
- if ( error != kKEXTReturnSuccess ) {
- return error;
- }
-
- _kextd = kextd;
-
- if( cdMKextBoot) {
- KEXTDScanPaths(kextd, true);
- return kKEXTReturnSuccess;
- }
-
- // FIXME: Need a way to make this synchronous!
- error = KERN2KEXTReturn(IOCatalogueSendData(k->_catPort, kIOCatalogRemoveKernelLinker, 0, 0));
- if (error != kKEXTReturnSuccess) {
- syslog(LOG_ERR, "couldn't remove linker from kernel (may have been removed already).",
- error);
- // this is only serious the first time kextd launches....
- // FIXME: how exactly should we handle this? Create a separate program
- // to trigger KLD unload?
- }
-
- signal(SIGHUP, signalhandler);
-
- k->_runloop = CFRunLoopGetCurrent();
- if ( !k->_runloop ) {
- syslog(LOG_ERR, "error allocating runloop.\n");
- return NULL;
- }
-
- sourceContext.version = 0;
- sourceContext.info = k;
- sourceContext.perform = _KEXTDSIGHUPCallout;
- k->_signalsource = CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &sourceContext);
- if ( !k->_signalsource ) {
- syslog(LOG_ERR, "error allocating signal runloop source.\n");
- return NULL;
- }
- CFRunLoopAddSource(k->_runloop, k->_signalsource, kCFRunLoopDefaultMode);
-
- sourceContext.perform = _KEXTDPerform;
- k->_kernelsource = CFRunLoopSourceCreate(kCFAllocatorDefault, 2, &sourceContext);
- if ( !k->_kernelsource ) {
- syslog(LOG_ERR, "error allocating kernel runloop source.\n");
- return NULL;
- }
- CFRunLoopAddSource(k->_runloop, k->_kernelsource, kCFRunLoopDefaultMode);
-
- count = CFArrayGetCount(k->_helpers);
- for ( i = 0; i < count; i++ ) {
- KEXTDHelper * helper;
-
- helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
- if ( !helper )
- continue;
-
- if ( helper->cbs.DaemonDidFinishLaunching )
- helper->cbs.DaemonDidFinishLaunching(helper->context);
- }
-
- // Fork off the kmod_control message thread.
- pthread_attr_init(&kmod_thread_attr);
- pthread_create(&kmod_thread, &kmod_thread_attr, _KEXTDKmodWait, kextd);
- pthread_detach(kmod_thread);
-
- syslog(LOG_INFO, "started.");
-
- IOCatalogueReset(k->_catPort, kIOCatalogResetDefault);
- KEXTDScanPaths(kextd, false);
-
-#if TIMERSOURCE
- if ( poll ) {
- CFRunLoopTimerRef timer;
- CFRunLoopTimerContext timerContext = {
- 0, kextd, NULL, NULL, NULL,
- };
-
- timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), period, 0, 10, _KEXTDTimerCallout, &timerContext);
- if ( !timer ) {
- syslog(LOG_ERR, "error allocating kmod runloop timer.\n");
- return kKEXTReturnError;
- }
-
- CFRunLoopAddTimer(k->_runloop, timer, kCFRunLoopDefaultMode);
- CFRelease(timer);
- }
-#endif
-
- if ( (error = _KEXTDSendPersonalities(kextd, bootlevel)) != kKEXTReturnSuccess ) {
- // KEXTError(error, CFSTR("Error sending personalities to IOCatalogue"));
- syslog(LOG_ERR, "error (%d) sending personalities to IOCatalogue.", error);
- return error;
- }
-
- k->_initializing = false;
-
- CFRunLoopRun();
-
- return kKEXTReturnSuccess;
-}
-
-void KEXTDScanPaths(KEXTDRef kextd, Boolean cdMKextBoot)
-{
- KEXTReturn error;
- KEXTD * k;
- CFIndex count;
- CFIndex i;
-
- k = (KEXTD *)kextd;
- if ( !k->_manager )
- return;
-
- count = CFArrayGetCount(k->_scanPaths);
- for ( i = 0; i < count; i++ ) {
- CFURLRef url;
-
- url = (CFURLRef)CFArrayGetValueAtIndex(k->_scanPaths, i);
-
- if ( url ) {
- if ( k->_beVerbose ) {
- CFStringRef cfstr;
- char str[256];
-
- cfstr = CFURLGetString(url);
- if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
- syslog(LOG_INFO, "scanning: %s.", str);
- }
- }
- if( !cdMKextBoot) {
- error = KEXTManagerScanPath(k->_manager, url);
- if ( error != kKEXTReturnSuccess ) {
- syslog(LOG_ERR, "error (%d) scanning path.\n", error);
- }
- }
-#if LOOKAPPLENDRV
- do {
- CFURLRef path;
- CFArrayRef array;
- CFIndex count, index;
- SInt32 err;
-
- path = CFURLCreateCopyAppendingPathComponent(
- kCFAllocatorDefault,
- url,
- CFSTR("AppleNDRV"),
- TRUE);
- if ( !path )
- continue;
- array = (CFArrayRef)IOURLCreatePropertyFromResource(
- kCFAllocatorDefault, path,
- kIOURLFileDirectoryContents,
- &err);
- CFRelease( path );
- if ( !array )
- continue;
-
- count = CFArrayGetCount(array);
- for ( index = 0; index < count; index++ ) {
- CFURLRef file;
- file = (CFURLRef) CFArrayGetValueAtIndex(array, index);
- if ( !file )
- continue;
- PEFExamineFile( k->_catPort, file );
- }
- CFRelease(array);
-
- } while( false );
-#endif /* LOOKAPPLENDRV */
- }
- }
-}
-
-void KEXTDAddScanPath(KEXTDRef kextd, CFURLRef path)
-{
- if ( !kextd || !path )
- return;
-
- if ( CFURLGetTypeID() != CFGetTypeID(path) )
- return;
-
- CFArrayAppendValue(((KEXTD *)kextd)->_scanPaths, path);
-}
-
-void KEXTDRegisterHelperCallbacks(KEXTDRef kextd, KEXTDHelperCallbacks * callbacks)
-{
- KEXTD * k;
- KEXTDHelper * helper;
-
- if ( !kextd || !callbacks )
- return;
-
- k = (KEXTD *)kextd;
- helper = (KEXTDHelper *)malloc(sizeof(KEXTDHelper));
- if ( !helper )
- return;
-
- helper->cbs.HelperInitialize = callbacks->HelperInitialize;
- helper->cbs.HelperFinalize = callbacks->HelperFinalize;
- helper->cbs.DaemonDidFinishLaunching = callbacks->DaemonDidFinishLaunching;
- helper->cbs.DaemonWillTerminate = callbacks->DaemonWillTerminate;
- helper->cbs.BundleAdd = callbacks->BundleAdd;
- helper->cbs.BundleRemove = callbacks->BundleRemove;
- helper->cbs.EventOccurred = callbacks->EventOccurred;
- helper->cbs.ModuleWillLoad = callbacks->ModuleWillLoad;
- helper->cbs.ModuleWasLoaded = callbacks->ModuleWasLoaded;
- helper->cbs.ModuleLoadError = callbacks->ModuleLoadError;
-
- helper->context = helper->cbs.HelperInitialize(kextd);
-
- CFArrayAppendValue(k->_helpers, helper);
-}
-
-KEXTReturn KEXTDLoadModule(KEXTDRef kextd, CFStringRef moduleName)
-{
- KEXTD * k = (KEXTD *)kextd;
- KEXTModuleRef module;
-
- if ( !kextd || !moduleName )
- return kKEXTReturnBadArgument;
-
- module = KEXTManagerGetModule(k->_manager, moduleName);
- if ( !module )
- return kKEXTReturnModuleNotFound;
-
- return KEXTManagerLoadModule(k->_manager, module);
-}
-
-
+++ /dev/null
-
-#ifndef __KEXTD_H_
-#define __KEXTD_H_
-
-#include <IOKit/kext/KEXTManager.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-typedef struct __KEXTD * KEXTDRef;
-
-typedef enum {
- kKEXTBootlevelNormal = 0x00,
- kKEXTBootlevelExempt = 0x01,
- kKEXTBootlevelRecovery = 0x02,
- kKEXTBootlevelSingleUser = 0x04,
- kKEXTBootlevelFlexible = 0x08,
- kKEXTBootlevelRequired = 0x10,
-} KEXTBootlevel;
-
-typedef enum {
- kKEXTEventReset,
- kKEXTEventModuleRequest,
- kKEXTEventPersonalityRequest,
- kKEXTEventBundleAuthenticationFailed,
-} KEXTEvent;
-
-typedef struct {
- CFIndex version;
- void * (*HelperInitialize)(KEXTDRef kextd);
- void (*HelperFinalize)(void * context);
- void (*DaemonDidFinishLaunching)(void * context);
- void (*DaemonWillTerminate)(void * context);
- Boolean (*BundleAdd)(KEXTBundleRef bundle, void * context);
- Boolean (*BundleRemove)(KEXTBundleRef bundle, void * context);
- void (*EventOccurred)(KEXTEvent event, CFTypeRef data, void * context);
- Boolean (*ModuleWillLoad)(KEXTModuleRef module, void * context);
- void (*ModuleWasLoaded)(KEXTModuleRef module, void * context);
- KEXTReturn (*ModuleLoadError)(KEXTModuleRef module, KEXTReturn error, void * context);
-} KEXTDHelperCallbacks;
-
-
-KEXTDRef KEXTDCreate(CFArrayRef scanPaths, KEXTReturn * error);
-void KEXTDFree(KEXTDRef kextd);
-
-void KEXTDHangup(KEXTDRef kextd);
-void KEXTDReset(KEXTDRef kextd);
-#if TIMERSOURCE
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel, Boolean cdMKextBoot);
-#else
-KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel, Boolean cdMKextBoot);
-#endif
-void KEXTDScanPaths(KEXTDRef kextd, Boolean cdMKextBoot);
-void KEXTDAddScanPath(KEXTDRef kextd, CFURLRef path);
-void KEXTDRegisterHelperCallbacks(KEXTDRef kextd, KEXTDHelperCallbacks * callbacks);
-KEXTReturn KEXTDKernelRequest(KEXTDRef kextd, CFStringRef moduleName);
-KEXTReturn KEXTDLoadModule(KEXTDRef kextd, CFStringRef moduleName);
-
-#if defined(__cplusplus)
-} /* "C" */
-#endif
-
-#endif __KEXTD_H_
-
+++ /dev/null
-#include <unistd.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include "KEXTD.h"
-
-#define TIMER_PERIOD_S 10
-#define DEFAULT_SEARCH_PATH "/System/Library/Extensions/"
-
-static const char * arg0 = NULL;
-
-static void usage(void)
-{
- printf("usage: %s [-v] [-d] [-x] [-j] [-b bootlevel] [-f dirpath]\n", arg0);
- exit(1);
-}
-
-int main (int argc, const char *argv[])
-{
- KEXTDRef kextd;
- KEXTReturn error;
- KEXTBootlevel bootlevel;
- CFStringRef str;
- CFURLRef url;
- CFMutableArrayRef array;
- CFIndex period;
- Boolean safeBoot;
- Boolean beVerbose;
- Boolean enableTimer;
- Boolean debug;
- Boolean cdMKextBoot;
- int c;
-
- arg0 = argv[0];
- period = TIMER_PERIOD_S;
- debug = false;
- safeBoot = false;
- beVerbose = false;
- enableTimer = false;
- cdMKextBoot = false;
- bootlevel = kKEXTBootlevelNormal;
-
- url = CFURLCreateWithFileSystemPath(NULL, CFSTR(DEFAULT_SEARCH_PATH), kCFURLPOSIXPathStyle, true);
- if ( !url ) {
- printf("Error opening: %s.\n", DEFAULT_SEARCH_PATH);
- exit(1);
- }
- array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFArrayAppendValue(array, url);
- CFRelease(url);
-
- while ( (c = getopt(argc, (char **)argv, "xvdjb:f:")) != -1 ) {
- switch ( c ) {
-
- case 'x':
- safeBoot = true;
- break;
- case 'v':
- beVerbose = true;
- break;
- case 'd':
- debug = true;
- break;
-#if TIMERSOURCE
- case 'p':
- if ( !optarg ) {
- usage();
- }
- else {
- period = strtoul(optarg, NULL, 0);
- if ( period > 0 )
- enableTimer = true;
- }
- break;
-#endif
-
- case 'b':
- if ( !optarg ) {
- usage();
- }
- bootlevel = strtoul(optarg, NULL, 0);
- if ( bootlevel > 0x1f ) {
- usage();
- }
- break;
-
- case 'j':
- cdMKextBoot = true;
- break;
-
- case 'f':
- if ( !optarg ) {
- usage();
- }
- str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingNonLossyASCII);
- if ( str )
- url = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, true);
- else
- url = NULL;
- if ( !url ) {
- printf("Error opening: %s.\n", optarg);
- } else {
- CFArrayAppendValue(array, url);
- CFRelease(url);
- }
- break;
-
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 0) {
- usage();
- }
-
- kextd = KEXTDCreate(array, &error);
- CFRelease(array);
- if ( !kextd ) {
- KEXTError(error, CFSTR("Error creating kextd"));
- exit(error);
- }
-
- KEXTDRegisterHelperCallbacks(kextd, NULL);
-#if TIMERSOURCE
- error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, enableTimer, period, bootlevel, cdMKextBoot);
-#else
- error = KEXTDStartMain(kextd, beVerbose, safeBoot, debug, bootlevel, cdMKextBoot);
-#endif
- if ( error != kKEXTReturnSuccess ) {
- KEXTDFree(kextd);
- KEXTError(error, CFSTR("Error starting kextd"));
- exit(error);
- }
- KEXTDFree(kextd);
-
- return error;
-}
+++ /dev/null
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kextd
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-HFILES = GetSymbolFromPEF.h KEXTD.h PTLock.h
-
-CFILES = KEXTD.c KEXTD_main.c PEFSupport.c PTLock.c
-
-OTHERSRCS = Makefile.preamble Makefile
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /usr/libexec
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-NEXTSTEP_PB_CFLAGS = -fpascal-strings -Wno-four-char-constants
-
-FRAMEWORKS = -framework CoreFoundation -framework IOKit
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = (CoreFoundation.framework, IOKit.framework);
- FRAMEWORKSEARCH = ();
- H_FILES = (GetSymbolFromPEF.h, KEXTD.h, PTLock.h);
- OTHER_LINKED = (KEXTD.c, KEXTD_main.c, PEFSupport.c, PTLock.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile);
- SUBPROJECTS = ();
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_COMPILEROPTIONS = "-fpascal-strings -Wno-four-char-constants";
- NEXTSTEP_INSTALLDIR = /usr/libexec;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kextd;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- File: UnpackPiData.c
- Written by: Jeffrey Robbin
- Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved.
-
- File: GetSymbolFromPEF.c
- Written by: Jeffrey Robbin
- Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved.
-*/
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/kext/KEXTManager.h>
-#include <stdlib.h>
-#include <err.h>
-#include <sys/file.h>
-#include <nlist.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include <paths.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-#include <mach/mach_host.h>
-
-#include "GetSymbolFromPEF.h"
-
-static unsigned char
-PEFGetNextByte (unsigned char** rawBuffer, long* rawBufferRemaining)
-{
- *rawBufferRemaining = *rawBufferRemaining - 1;
- return *(*rawBuffer)++;
-}
-
-
-static unsigned long
-PEFGetCount(unsigned char** rawBuffer, long* rawBufferRemaining)
-{
- register unsigned char b;
- register unsigned long value = 0UL;
-
- /* Scan the count value. All required bytes MUST be present... */
-
- b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
- if (!IS_LAST_PICNT_BYTE(b)) { /* if 1st byte is not that last... */
- value = CONCAT_PICNT(value, b); /* ...init value using 1st byte */
-
- b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
- if (!IS_LAST_PICNT_BYTE(b)) { /* if 2nd byte is not the last... */
- value = CONCAT_PICNT(value, b); /* ...add in 2nd byte */
-
- b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
- if (!IS_LAST_PICNT_BYTE(b)) { /* if 3rd byte is not the last... */
- value = CONCAT_PICNT(value, b); /* ...add in 3rd byte */
-
- b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
- if (!IS_LAST_PICNT_BYTE(b)) { /* if 4th byte is not the last... */
- value = CONCAT_PICNT(value, b); /* ...add in 4th byte */
-
- /* 5th byte is definitly last! */
- b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
- }
- }
- }
- }
-
-value = CONCAT_PICNT(value, b); /* add in "last" byte (whichever one) */
-
-return (value);
-}
-
-
-
-// UnpackPiData expands a compressed section into memory.
-
-static OSErr
-UnpackPiData (LogicalAddress thePEFPtr,
- SectionHeaderPtr sectionHeaderPtr,
- LogicalAddress* theData)
-{
- long cntX, cnt, rpt, dcnt, delta;
- unsigned char op, b;
- unsigned char* unpackBuffer;
- unsigned char* originalUnpackBuffer;
- unsigned char* endUnpackBuffer;
- unsigned char* oldRawBuffer;
- long oldRawBufferRemaining;
- unsigned char* rawBuffer;
- long rawBufferRemaining;
-
- // Verify incoming section is packed.
- if (sectionHeaderPtr->regionKind != kPIDataSection)
- return (paramErr);
-
-
- // Allocate memory to unpack into
- originalUnpackBuffer = (unsigned char*)NewPtrSys(sectionHeaderPtr->initSize);
- if (originalUnpackBuffer == nil)
- return memFullErr;
-
- unpackBuffer = originalUnpackBuffer;
- endUnpackBuffer = unpackBuffer + sectionHeaderPtr->initSize;
- rawBuffer = (unsigned char*)((unsigned long)thePEFPtr + sectionHeaderPtr->containerOffset);
- rawBufferRemaining = sectionHeaderPtr->rawSize;
-
-
- /* Expand the pidata instructions. EOF will terminate processing through the setjmp */
- /* on pidData_jmpbuf above... */
-
- while (rawBufferRemaining > 0) {
-
- /* The first byte of each instruction contains the opcode and a count. If the count */
- /* is 0, the count starts in the next byte... */
-
- /* Pick up the opcode and first count operand... */
-
- b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
-
- op = PIOP(b);
- cnt = PICNT(b);
-
- if (cnt == 0)
- cnt = PEFGetCount(&rawBuffer, &rawBufferRemaining);
-
- /* Unpack the data as a function of the opcode... */
-
- switch (op) {
- case kZero: /* zero out cnt bytes...*/
- if (unpackBuffer + cnt > endUnpackBuffer)
- goto Error;
- memset(unpackBuffer, 0, cnt);
- unpackBuffer += cnt;
- break;
-
- case kBlock: /* copy cnt bytes...*/
- if (unpackBuffer + cnt > endUnpackBuffer)
- goto Error;
- while (--cnt >= 0)
- *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
- break;
-
- case kRepeat: /* copy cnt bytes rpt times...*/
- rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining) + 1;
-
- if (cnt == 1)
- {
- if (unpackBuffer + rpt > endUnpackBuffer)
- goto Error;
- b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
- memset(unpackBuffer, b, rpt);
- unpackBuffer += rpt;
- }
- else
- {
- oldRawBufferRemaining = rawBufferRemaining;
- oldRawBuffer = rawBuffer;
- while (--rpt >= 0) {
- if (unpackBuffer + cnt > endUnpackBuffer)
- goto Error;
- rawBufferRemaining = oldRawBufferRemaining;
- rawBuffer = oldRawBuffer;
- cntX = cnt;
- while (--cntX >= 0)
- *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
- }
- }
- break;
-
- case kRepeatZero: /* copy cnt 0's and dcnt bytes rpt times*/
- dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); /* ...then copy cnt more 0's */
- rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining);
-
- goto rptPart1; /* jump into loop to copy 0's first... */
-
- while (--rpt >= 0) {
- if (unpackBuffer + dcnt > endUnpackBuffer)
- goto Error;
- cntX = dcnt; /* cnt repeating parts follow each other*/
- while (--cntX >= 0)
- *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
-rptPart1: /* non-repeating part is always 0's... */
- if (unpackBuffer + cnt > endUnpackBuffer)
- goto Error;
- memset(unpackBuffer, 0, cnt);
- unpackBuffer += cnt;
- }
-
- break;
-
- case kRepeatBlock: /* copy cnt repeating bytes and dcnt */
- dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); /* non-repating bytes rcnt times... */
- rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining); /* ...then copy cnt repeating bytes */
-
- oldRawBufferRemaining = rawBufferRemaining;
- oldRawBuffer = rawBuffer;
- delta = 0; /* the repeating part and each non-rep */
-
- goto rptPart2; /* jump into loop to copy rptng part 1st*/
-
- while (--rpt >= 0) {
- if (unpackBuffer + dcnt > endUnpackBuffer)
- goto Error;
-
- rawBuffer = oldRawBuffer + cnt + delta;
- rawBufferRemaining = oldRawBufferRemaining - (cnt + delta);
- cntX = dcnt;
- while (--cntX >= 0)
- *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
- delta += dcnt;
-rptPart2:
- if (unpackBuffer + cnt > endUnpackBuffer)
- goto Error;
- rawBuffer = oldRawBuffer;
- rawBufferRemaining = oldRawBufferRemaining;
- cntX = cnt;
- while (--cntX >= 0)
- *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
- }
-
- rawBuffer = oldRawBuffer + cnt + delta;
- rawBufferRemaining = oldRawBufferRemaining - (cnt + delta);
- break;
-
- default:
- goto Error;
- } /* switch */
- } /* for */
-
- *theData = originalUnpackBuffer;
-
- return noErr;
-
-Error:
- if (unpackBuffer)
- DisposePtr((Ptr)originalUnpackBuffer);
-
- *theData = nil;
-
- return paramErr;
-}
-
-// GetSymbolFromPEF will extract from a PEF container the data associated
-// with a given symbol name. It requires that the PEF file have been previously
-// loaded into memory.
-
-static OSStatus
-GetSymbolFromPEF( StringPtr theSymbolName,
- const LogicalAddress thePEFPtr,
- LogicalAddress theSymbolPtr,
- ByteCount theSymbolSize )
-{
- ContainerHeaderPtr containerHeaderPtr; // Pointer to the Container Header
- SectionHeaderPtr loaderSectionPtr; // Pointer to the Loader Section Header
- SectionHeaderPtr exportSectionPtr; // Pointer to the Section Header with the symbol
- short currentSection;
- Boolean foundSection;
- Boolean foundSymbol;
- long numExportSymbols;
- LoaderHeaderPtr loaderHeaderPtr;
- ExportSymbolEntryPtr exportSymbolEntryPtr;
- LoaderExportChainEntryPtr exportChainEntryPtr;
- StringPtr exportSymbolName;
- LogicalAddress expandedDataPtr;
- unsigned char* sourceDataPtr;
- unsigned char* destDataPtr;
-
-
- containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr;
-
- // Does the magic cookie match?
- if (containerHeaderPtr->magicCookie != 'Joy!')
- return cfragFragmentFormatErr;
-
- // Is this a known PEF container format?
- if (containerHeaderPtr->containerID != 'peff')
- return cfragFragmentFormatErr;
-
- // Validate parameters
- if (theSymbolPtr == nil)
- return paramErr;
-
-
- // Find the loader section.
- foundSection = false;
- for (currentSection = 0; currentSection < containerHeaderPtr->nbrOfSections; currentSection++)
- {
- loaderSectionPtr = (SectionHeaderPtr)( (unsigned long)containerHeaderPtr +
- sizeof(ContainerHeader) +
- (sizeof(SectionHeader) * currentSection));
- if (loaderSectionPtr->regionKind == kLoaderSection)
- {
- foundSection = true;
- break;
- }
- }
-
- if (foundSection == false)
- return cfragNoSectionErr;
-
- // Get the number of export symbols.
- loaderHeaderPtr = (LoaderHeaderPtr)((unsigned long)thePEFPtr + loaderSectionPtr->containerOffset);
- numExportSymbols = loaderHeaderPtr->nbrExportSyms;
-
- // Start at the first exported symbol.
- exportSymbolEntryPtr = (ExportSymbolEntryPtr)( (unsigned long)loaderHeaderPtr +
- loaderHeaderPtr->slotTblOffset +
- (sizeof(LoaderHashSlotEntry) * (1<<loaderHeaderPtr->hashSlotTblSz)) +
- (sizeof(LoaderExportChainEntry) * numExportSymbols));
-
- exportChainEntryPtr = (LoaderExportChainEntryPtr)( (unsigned long)loaderHeaderPtr +
- loaderHeaderPtr->slotTblOffset +
- (sizeof(LoaderHashSlotEntry) * (1<<loaderHeaderPtr->hashSlotTblSz)));
-
- foundSymbol = false;
- while (numExportSymbols-- > 0)
- {
- exportSymbolName = (StringPtr)( (unsigned long)loaderHeaderPtr +
- loaderHeaderPtr->strTblOffset +
- (exportSymbolEntryPtr->class_and_name & 0x00FFFFFF));
- if (SymbolCompare(theSymbolName, exportSymbolName, exportChainEntryPtr->_h._h_h._nameLength))
- {
- foundSymbol = true;
- break;
- }
- exportSymbolEntryPtr = (ExportSymbolEntryPtr)(((int)exportSymbolEntryPtr) + 10);
- exportChainEntryPtr++;
- }
-
- if (foundSymbol == false)
- return cfragNoSymbolErr;
-
-
- // Found the symbol, so... let's go get the data!
-
- exportSectionPtr = (SectionHeaderPtr)( (unsigned long)containerHeaderPtr +
- sizeof(ContainerHeader) +
- (sizeof(SectionHeader) * exportSymbolEntryPtr->sectionNumber));
-
- expandedDataPtr = nil;
-
- switch (exportSectionPtr -> regionKind)
- {
- case kPIDataSection:
-
- // Expand the data! (Not yet... :)
-
- if (UnpackPiData (thePEFPtr, exportSectionPtr, &expandedDataPtr) != noErr)
- return cfragFragmentCorruptErr;
-
- sourceDataPtr = (unsigned char*)((unsigned long)expandedDataPtr +
- exportSymbolEntryPtr->address);
- break;
-
- default:
- sourceDataPtr = (unsigned char*)((unsigned long)thePEFPtr +
- exportSectionPtr->containerOffset +
- exportSymbolEntryPtr->address);
- break;
- }
-
-
- // Copy the data!
-
- destDataPtr = (unsigned char*)theSymbolPtr;
-
-
- while (theSymbolSize-- > 0)
- *destDataPtr++ = *sourceDataPtr++;
-
-
- // Cleanup any expanded data
-
- if (expandedDataPtr != nil)
- DisposePtr((Ptr)expandedDataPtr);
-
- return noErr;
-}
-
-
-static IOByteCount GetPEFLen ( LogicalAddress thePEFPtr)
-{
- ContainerHeaderPtr containerHeaderPtr; // Pointer to the Container Header
- SectionHeaderPtr sections;
- short currentSection;
- long lastOffset = 0;
- long len = 0;
-
- containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr;
-
- // Does the magic cookie match?
- if (containerHeaderPtr->magicCookie != 'Joy!')
- return 0;
-
- // Is this a known PEF container format?
- if (containerHeaderPtr->containerID != 'peff')
- return 0;
-
- // Find the loader section.
- sections = (SectionHeaderPtr) (containerHeaderPtr + 1);
- for (currentSection = 0; currentSection < containerHeaderPtr->nbrOfSections; currentSection++)
- {
- if( sections[currentSection].containerOffset > lastOffset) {
- lastOffset = sections[currentSection].containerOffset;
- len = sections[currentSection].rawSize;
- }
- }
-
- return( lastOffset + len );
-}
-
-//
-// SymbolCompare
-//
-// theExportSymbol is NOT null-terminated, so use theExportSymbolLength.
-//
-static Boolean SymbolCompare ( StringPtr theLookedForSymbol,
- StringPtr theExportSymbol,
- unsigned long theExportSymbolLength)
-{
- unsigned char* p1 = (unsigned char*)theLookedForSymbol;
- unsigned char* p2 = (unsigned char*)theExportSymbol;
-
- // Same length?
- // (skip over p string len byte)
- if ( theExportSymbolLength != *p1++ )
- return false;
-
- while ( theExportSymbolLength-- != 0 )
- {
- if ( *p1++ != *p2++ )
- return false;
- }
-
- return true;
-}
-
-static int
-readFile(char *path, char **objAddr, long *objSize)
-{
- int fd;
- int err;
- struct stat stat_buf;
-
- *objAddr = 0;
- *objSize = 0;
-
- if((fd = open(path, O_RDONLY)) == -1)
- return errno;
-
- do {
- if(fstat(fd, &stat_buf) == -1) {
- err = errno;
- continue;
- }
- *objSize = stat_buf.st_size;
-
- if( KERN_SUCCESS != map_fd(fd, 0, (vm_offset_t *) objAddr, TRUE, *objSize)) {
- *objAddr = 0;
- *objSize = 0;
- err = errno;
- continue;
- }
-
- err = 0;
-
- } while( false );
-
- close(fd);
-
- return( err );
-}
-
-
-// The Driver Description
-enum {
- kInitialDriverDescriptor = 0,
- kVersionOneDriverDescriptor = 1,
- kTheDescriptionSignature = 'mtej',
-};
-
-struct DriverType {
- unsigned char nameInfoStr[32]; // Driver Name/Info String
- unsigned long version; // Driver Version Number - really NumVersion
-};
-typedef struct DriverType DriverType;
-
-struct DriverDescription {
- unsigned long driverDescSignature; // Signature field of this structure
- unsigned long driverDescVersion; // Version of this data structure
- DriverType driverType; // Type of Driver
- char otherStuff[512];
-};
-typedef struct DriverDescription DriverDescription;
-
-static void
-ExaminePEF( mach_port_t masterPort, char *pef, IOByteCount pefLen, CFArrayRef okList )
-{
- char descripName[] = "\pTheDriverDescription";
- long err;
- DriverDescription descrip;
- DriverDescription curDesc;
- char matchName[40];
- char okName[40];
- unsigned long newVersion;
- unsigned long curVersion;
- IOReturn kr;
- io_iterator_t iter;
- io_service_t service;
- io_service_t child;
- io_string_t path;
- CFStringRef ndrvPropName = CFSTR("driver,AAPL,MacOS,PowerPC");
- CFDataRef ndrv;
- CFMutableDictionaryRef dict;
- CFIndex index;
- CFStringRef okStr;
- Boolean ok;
-
- err = GetSymbolFromPEF(descripName, pef, &descrip, sizeof(descrip));
- if(err != 0) {
- printf("\nGetSymbolFromPEF returns %ld\n",err);
- return;
- }
- if((descrip.driverDescSignature != kTheDescriptionSignature) ||
- (descrip.driverDescVersion != kInitialDriverDescriptor))
- return;
-
- strncpy(matchName, descrip.driverType.nameInfoStr + 1,
- descrip.driverType.nameInfoStr[0]);
- matchName[ descrip.driverType.nameInfoStr[0] ] = 0;
-
- ok = (!okList);
- for( index = 0; (!ok) && (index < CFArrayGetCount(okList)); index++) {
- okStr = CFArrayGetValueAtIndex( okList, index);
- if( CFStringGetTypeID() != CFGetTypeID(okStr))
- continue;
- ok = CFStringGetCString( okStr, okName, sizeof(okName),
- kCFStringEncodingMacRoman)
- && (0 == strcmp( okName, matchName));
- }
-
- newVersion = descrip.driverType.version;
- if((newVersion & 0xffff) == 0x8000) // final stage, release rev
- newVersion |= 0xff;
-
- IOMasterPort(mach_task_self(), &masterPort);
-
- kr = IOServiceGetMatchingServices(masterPort,
- IOServiceNameMatching(matchName),
- &iter);
- if( kIOReturnSuccess != kr)
- return;
-
- for(
- ;
- (service = IOIteratorNext(iter));
- IOObjectRelease(service)) {
-
- kr = IORegistryEntryGetPath( service, kIOServicePlane, path );
- if( kIOReturnSuccess == kr)
- printf("Name %s matches %s, ", matchName, path);
- if( !ok) {
- printf("(skipping)\n");
- continue;
- }
-
- ndrv = (CFDataRef) IORegistryEntryCreateCFProperty( service, ndrvPropName,
- kCFAllocatorDefault, kNilOptions );
-
- if( ndrv) {
- err = GetSymbolFromPEF( descripName, CFDataGetBytePtr(ndrv),
- &curDesc, sizeof(curDesc));
- if (err != noErr)
- printf("GetSymbolFromPEF returns %ld\n",err);
- else {
- if((curDesc.driverDescSignature == kTheDescriptionSignature) &&
- (curDesc.driverDescVersion == kInitialDriverDescriptor)) {
-
- curVersion = curDesc.driverType.version;
- printf("new version %08lx, current version %08lx\n", newVersion, curVersion);
- if((curVersion & 0xffff) == 0x8000) // final stage, release rev
- curVersion |= 0xff;
-
- if( newVersion <= curVersion)
- pefLen = 0;
- }
- }
- CFRelease(ndrv);
- }
-
- if( pefLen == 0)
- continue;
-
- ndrv = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
- pef, pefLen, kCFAllocatorNull);
- if( ndrv == 0)
- continue;
- printf("Installing ndrv (");
- dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- if( dict) {
- CFDictionarySetValue(dict, ndrvPropName, ndrv);
- kr = IORegistryEntryGetChildEntry( service, kIOServicePlane, &child );
- if( kr == kIOReturnSuccess) {
- kr = IORegistryEntrySetCFProperties( child, dict );
- IOObjectRelease( child );
- }
- CFRelease( dict);
- } else
- kr = kIOReturnNoMemory;
-
- CFRelease(ndrv);
- printf("%08x)\n", kr);
- }
- IOObjectRelease( iter );
-
- return;
-}
-
-int
-PEFExamineFile( mach_port_t masterPort, CFURLRef file )
-{
- char * pefBytes;
- char * plistBytes;
- char * pef;
- long pefFileLen, plistLen;
- IOByteCount pefLen, pos = 0;
- int err;
- CFDictionaryRef props = 0;
- CFDataRef data = 0;
- CFArrayRef okList = 0;
- enum { kIOCFMaxPathSize = 1026 };
- char cFile[kIOCFMaxPathSize];
-
- if (CFURLGetFileSystemRepresentation(file, TRUE, cFile, kIOCFMaxPathSize))
- err = readFile(cFile, &pefBytes, &pefFileLen);
- else
- err = kIOReturnIOError;
- if( err)
- return( err);
-
- do {
- strcat( cFile, ".plist");
- err = readFile(cFile, &plistBytes, &plistLen);
- if( err)
- continue;
-
- data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault,
- plistBytes, plistLen, kCFAllocatorNull);
- if( !data)
- continue;
- props = (CFDictionaryRef) CFPropertyListCreateFromXMLData(
- kCFAllocatorDefault, data, kCFPropertyListImmutable, 0 );
- if( !props)
- continue;
- if( CFDictionaryGetTypeID() != CFGetTypeID(props))
- continue;
-
- okList = CFDictionaryGetValue( props, CFSTR("IONDRVList") );
- if( CFArrayGetTypeID() != CFGetTypeID(okList))
- okList = 0;
-
- } while( false );
-
- pef = pefBytes;
- while( (pos < pefFileLen) && (pefLen = GetPEFLen( pef ))) {
- ExaminePEF( masterPort, pef, pefLen, okList );
- pefLen = (pefLen + 15) & ~15;
- pef += pefLen;
- pos += pefLen;
- }
-
- if( data)
- CFRelease(data);
- if( props)
- CFRelease(props);
-
- if( plistBytes)
- vm_deallocate( mach_task_self(), (vm_address_t) plistBytes, plistLen );
- if( pefBytes)
- vm_deallocate( mach_task_self(), (vm_address_t) pefBytes, pefFileLen );
-
- return( 0 );
-}
-
-
-
+++ /dev/null
-
-#include <PTLock.h>
-#include <stdlib.h>
-#include <mach/message.h>
-
-#define mutex_t pthread_mutex_t
-#define condition_t pthread_cond_t
-
-#define mutex_init(m) pthread_mutex_init(m, NULL)
-#define mutex_free(m) pthread_mutex_destroy(m)
-#define mutex_lock(m) pthread_mutex_lock(m)
-#define mutex_unlock(m) pthread_mutex_unlock(m)
-
-#define condition_init(c) pthread_cond_init(c, NULL)
-#define condition_free(c) pthread_cond_destroy(c)
-#define condition_wait(c, m) pthread_cond_wait(c, m)
-#define condition_signal(c) pthread_cond_signal(c)
-#define condition_broadcast(c) pthread_cond_broadcast(c)
-
-
-typedef struct _PTLock {
- Boolean locked;
- pthread_mutex_t m;
- pthread_cond_t c;
-} PTLock;
-
-
-PTLockRef
-PTLockCreate(void)
-{
- PTLock * l;
-
- l = (PTLock *)malloc(sizeof(PTLock));
- if ( !l )
- return NULL;
-
- l->locked = false;
- mutex_init(&l->m);
- condition_init(&l->c);
-
- return (PTLockRef)l;
-}
-
-void
-PTLockFree(PTLockRef lock)
-{
- PTLock * l = (PTLock *)lock;
-
- if ( !lock )
- return;
-
- mutex_free(&l->m);
- condition_free(&l->c);
- free(lock);
-}
-
-void
-PTLockTakeLock(PTLockRef lock)
-{
- PTLock * l = (PTLock *)lock;
-
- mutex_lock(&l->m);
- while ( l->locked )
- condition_wait(&l->c, &l->m);
- l->locked = true;
- mutex_unlock(&l->m);
-}
-
-void
-PTLockUnlock(PTLockRef lock)
-{
- PTLock * l = (PTLock *)lock;
-
- mutex_lock(&l->m);
- l->locked = false;
- condition_signal(&l->c);
- mutex_unlock(&l->m);
-}
-
-Boolean
-PTLockTryLock(PTLockRef lock)
-{
- PTLock * l = (PTLock *)lock;
-
- Boolean ret;
-
- mutex_lock(&l->m);
- ret = !l->locked;
- if ( ret )
- l->locked = true;
- mutex_unlock(&l->m);
-
- return ret;
-}
-
+++ /dev/null
-
-#ifndef _PTLOCK_H_
-#define _PTLOCK_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <CoreFoundation/CFBase.h>
-#include <pthread.h>
-
-typedef struct __PTLock * PTLockRef;
-
-PTLockRef PTLockCreate(void);
-void PTLockFree(PTLockRef lock);
-
-Boolean PTLockTryLock(PTLockRef lock);
-void PTLockTakeLock(PTLockRef lock);
-void PTLockUnlock(PTLockRef lock);
-
-#ifdef __cplusplus
-}
-#endif
-#endif _PTLOCK_H_
-
+++ /dev/null
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kextload
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-CFILES = kextload_main.c
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kextload.8
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /sbin
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-FRAMEWORKS = -framework CoreFoundation -framework IOKit
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-MAN_PAGE = kextload.8
-MAN_PATH = /usr/share/man/man8
-
-after_install::
- -mkdir -p ${DSTROOT}$(MAN_PATH)
- -rm -f ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
- cp $(MAN_PAGE) ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
- chmod og-w ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
-
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = (CoreFoundation.framework, IOKit.framework);
- OTHER_LINKED = (kextload_main.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kextload.8);
- SUBPROJECTS = ();
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_INSTALLDIR = /sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kextload;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-.\"
-.\" Copyright (c) 1997 Doug Rabson
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (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: kextload.8,v 1.5 2001/01/19 22:51:09 lindak Exp $
-.\"
-.Dd October 11, 1999
-.Dt kextload 8
-.Os FreeBSD
-.Sh NAME
-.Nm kextload
-.Nd loads and starts a kernel extension
-.Sh SYNOPSIS
-.Nm kextload
-.Op Fl i
-.Op Fl v
-.Op Fl h
-.Op Fl x
-.Ar kextbundle
-.Sh DESCRIPTION
-The
-.Nm
-utility loads the module files contained within
-.Ar kextbundle
-into the kernel and starts their execution either by calling a predefined initialization routine or by passing a personality description to the kernel. All module dependencies for
-.Ar kextbundle
-must reside in /System/Library/Extensions.
-.Pp
-The following options are available:
-.Bl -tag -width indent
-.It Fl v
-Be more verbose.
-.It Fl v
-Simulate safe boot (for testing).
-.It Fl i
-Set interactive mode.
-.It Fl h
-Provide quick help.
-.El
-.Sh FILES
-.Bl -tag -width /modules -compact
-.It Pa /TBD
-directory (bundle) containing loadable kernel modules.
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success or with a nonzero status if an error occurs.
-.Sh SEE ALSO
-.Xr kmodload 8 ,
-.Xr kmodstat 8 ,
-.Xr kmodsyms 8 ,
-.Xr kmodunload 8
+++ /dev/null
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sysexits.h>
-#include <sys/wait.h>
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOKitServer.h>
-#include <IOKit/IOCFSerialize.h>
-#include <mach/mach_types.h>
-
-#include <IOKit/kext/KEXTManager.h>
-
-static Boolean sSafeBoot = false;
-static Boolean sVerbose = false;
-static Boolean sInteractive = false;
-static Boolean sAuthenticateAll = false;
-
-static KEXTManagerRef manager = NULL;
-static const char * sCmdName;
-
-#define kBundleIDKey "CFBundleIdentifier"
-#define kPersonalityNameKey "IOPersonalityName"
-
-#if 0
-// no longer (or never was!) used
-#define kModuleKey "Module"
-#define kModulesKey "Modules"
-#define kModuleFileKey "File"
-#define kPersonalityKey "Personality"
-#define kPersonalitiesKey "Personalities"
-#define kNameKey "Name"
-#define kVendorKey "Vendor"
-#define kVersionKey "Version"
-#define kRequiresKey "Requires"
-#define kModuleAliasesKey "Aliases"
-#endif 0
-
-#define kDefaultSearchPath "/System/Library/Extensions"
-
-// these don't seem to be used
-#if 0
-#define kInfoMacOS "Info-macos"
-#define kInfoMacOSType "xml"
-#endif 0
-
-static void usage(Boolean help)
-{
- fprintf(stderr, "Usage: %s [-eihvx] [[-L dir] ...] [-p personality] kextpath\n", sCmdName);
- if ( help ) {
- fprintf(stderr, "\t-e Don't scan System extensions.\n");
- fprintf(stderr, "\t-h Help (this menu).\n");
- fprintf(stderr, "\t-i Interactive mode.\n");
- fprintf(stderr, "\t-L Search Library dir.\n");
- fprintf(stderr, "\t-p Personality to load.\n");
- fprintf(stderr, "\t-v Verbose mode.\n");
- fprintf(stderr, "\t-x Run in safe boot mode.\n");
- }
- exit(EX_USAGE);
-}
-
-static void printError(const char * string)
-{
- fprintf(stderr, string);
- return;
-}
-
-static void printMessage(const char * string)
-{
- if (sVerbose) {
- fprintf(stdout, string);
- }
- return;
-}
-
-static Boolean Prompt(CFStringRef message, Boolean defaultValue)
-{
- Boolean ret;
- CFIndex len;
- char * buf;
- char * dp;
- char c;
- char dv;
-
- ret = false;
- len = CFStringGetLength(message) + 1;
- buf = (char *)malloc(sizeof(char) * len);
- if ( !CFStringGetCString(message, buf, len, kCFStringEncodingASCII) ) {
- free(buf);
- return false;
- }
-
- dv = defaultValue?'y':'n';
- dp = defaultValue?" [Y/n]":" [y/N]";
-
- while ( 1 ) {
- printf(buf);
- printf(dp);
- printf("? ");
- fflush(stdout);
- fscanf(stdin, "%c", &c);
- if ( c != 10 ) while ( fgetc(stdin) != 10 );
- if ( (c == 10) || (tolower(c) == dv) ) {
- ret = defaultValue;
- break;
- }
- else if ( tolower(c) == 'y' ) {
- ret = true;
- break;
- }
- else if ( tolower(c) == 'n' ) {
- ret = false;
- break;
- }
- }
- free(buf);
-
- return ret;
-}
-
-static CFURLRef
-URLCreateAbsoluteWithPath(CFStringRef path)
-{
- CFURLRef url, base;
-
- url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
- path, kCFURLPOSIXPathStyle, true);
- base = CFURLCopyAbsoluteURL(url); CFRelease(url);
- path = CFURLGetString(base);
-
- url = CFURLCreateWithString(kCFAllocatorDefault, path, NULL);
- CFRelease(base);
-
- return url;
-}
-
-// Override the default authentication scheme so we can load
-// kext not owned by root into the kernel.
-static KEXTReturn authenticate(CFURLRef url, void * context)
-{
- if ( !sAuthenticateAll ) {
- KEXTReturn ret;
-
- ret = KEXTManagerAuthenticateURL(url);
- if ( ret != kKEXTReturnSuccess ) {
- if ( sVerbose ) {
- CFURLRef absUrl;
- CFStringRef message;
- CFStringRef path;
-
- absUrl = CFURLCopyAbsoluteURL(url);
- path = CFURLGetString(absUrl);
-
- message = CFStringCreateWithFormat(
- kCFAllocatorDefault,
- NULL,
- CFSTR("Error (%d) Authentication failed: %@"),
- ret,
- path);
-
- CFShow(message);
- CFRelease(message);
- CFRelease(absUrl);
- }
- return ret;
- }
- }
-
- return kKEXTReturnSuccess;
-}
-
-// Print out a message when a module is about to load.
-static Boolean mWillLoad(KEXTManagerRef manager, KEXTModuleRef module, void * context)
-{
- CFStringRef name;
- CFStringRef message;
-
- if ( !sVerbose ) {
- return true;
- }
-
- name = (CFStringRef)KEXTModuleGetProperty(module, CFSTR(kBundleIDKey));
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Loading module: %@."), name);
- CFShow(message);
- CFRelease(message);
-
- return true;
-}
-
-// Print out a message when the module was successfully loaded.
-static void mWasLoaded(KEXTManagerRef manager, KEXTModuleRef module, void * context)
-{
- CFStringRef name;
- CFStringRef message;
-
- if ( !sVerbose ) {
- return;
- }
-
- name = (CFStringRef)KEXTModuleGetProperty(module, CFSTR(kBundleIDKey));
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Loaded module: %@."), name);
- CFShow(message);
- CFRelease(message);
-}
-
-// Print an error message if there was an error loading the module.
-static KEXTReturn mLoadError(KEXTManagerRef manager, KEXTModuleRef module, KEXTReturn error, void * context)
-{
- CFStringRef name;
- CFStringRef message;
-
- name = (CFStringRef)KEXTModuleGetProperty(module, CFSTR(kBundleIDKey));
- switch ( error ) {
- case kKEXTReturnModuleAlreadyLoaded:
-
- /* If the module was already loaded, that isn't an error
- * as far as kextload is concerned.
- */
- error = kKEXTReturnSuccess;
-
- if ( sVerbose ) {
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
- CFSTR("Module '%@' is already loaded; continuing."), name);
- CFShow(message);
- CFRelease(message);
- }
- break;
-
- default:
- if ( sVerbose ) {
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
- CFSTR("Error loading module '%@'"), name);
- KEXTError(error, message);
- CFRelease(message);
- }
- break;
- }
-
- return error;
-}
-
-// Initialize the KEXTManager.
-static Boolean InitManager(CFArrayRef libList)
-{
- CFStringRef scanpath;
- int i, count;
- CFURLRef url;
- KEXTReturn error;
- KEXTManagerBundleLoadingCallbacks bCallback = {
- 0, authenticate, NULL, NULL, NULL, NULL, NULL,
- };
- KEXTManagerModuleLoadingCallbacks mCallbacks = {
- 0, mWillLoad, mWasLoaded, mLoadError, NULL, NULL,
- };
-
- // Create the manager database.
- manager = KEXTManagerCreate(&bCallback, &mCallbacks, NULL, NULL, NULL, &printError, &printMessage, sSafeBoot, &error);
- if ( !manager ) {
- fprintf(stderr, "Manager not created.\n");
- return false;
- }
-
- for (i = 0, count = CFArrayGetCount(libList); i < count; i++) {
- scanpath = CFArrayGetValueAtIndex(libList, i);
- url = URLCreateAbsoluteWithPath(scanpath);
- // Now scan in all the bundles in the extensions directory.
- error = KEXTManagerScanPath(manager, url);
- CFRelease(url);
- if (error != kKEXTReturnSuccess) {
- if (sVerbose) {
- CFStringRef errMsg = CFStringCreateWithFormat(
- kCFAllocatorDefault,
- NULL,
- CFSTR("Error scanning path - %@"),
- scanpath);
- KEXTError(error, errMsg);
- }
- };
- }
-
- return true;
-}
-
-static void PromptForLoading(void * val, void * context)
-{
- KEXTPersonalityRef person;
- CFMutableArrayRef toLoad;
- Boolean boolval;
-
- person = val;
- toLoad = context;
-
- boolval = true;
- if ( sInteractive ) {
- CFStringRef name;
-
- name = KEXTPersonalityGetProperty(person, CFSTR(kBundleIDKey));
- if ( name ) {
- CFStringRef message;
-
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Load personality '%@'"), name);
- boolval = Prompt(message, true);
- CFRelease(message);
- }
- }
-
- if ( boolval ) {
- CFArrayAppendValue(toLoad, person);
- }
-}
-
-static void ArrayGetModuleList(void * val, void * context[])
-{
- KEXTPersonalityRef person;
- KEXTModuleRef module;
- KEXTReturn error;
- CFMutableArrayRef modules;
- CFStringRef name;
- CFStringRef modName;
- CFStringRef message;
-
- person = val;
- modules = context[0];
- error = *(KEXTReturn *)context[1];
-
- if ( error != kKEXTReturnSuccess ) {
- return;
- }
-
- // Once we have the personality entity, we can
- // attempt to load it into the kernel...
- modName = KEXTPersonalityGetProperty(person, CFSTR(kBundleIDKey));
- if ( !modName ) {
- name = KEXTPersonalityGetProperty(person, CFSTR(kBundleIDKey));
- message = CFStringCreateWithFormat(kCFAllocatorDefault,
- NULL,
- CFSTR("Error: '%@' has no Module key."),
- name);
- CFShow(message);
- CFRelease(message);
-
- if ( sInteractive ) {
- if ( !Prompt(CFSTR("Continue"), true) ) {
- *(KEXTReturn *)(context[1]) = error;
- return;
- }
- }
- return;
- }
-
- module = KEXTManagerGetModule(manager, modName);
- if ( module ) {
- CFRange range;
-
- range = CFRangeMake(0, CFArrayGetCount(modules));
- if ( !CFArrayContainsValue(modules, range, module) ) {
- CFArrayAppendValue(modules, module);
- }
- }
-}
-
-static void ArrayLoadMods(void * val, void * context)
-{
- KEXTModuleRef mod;
- KEXTReturn error;
- Boolean boolval;
-
- error = *(KEXTReturn *)context;
- if ( error != kKEXTReturnSuccess ) {
- return;
- }
-
- mod = val;
-
- boolval = true;
- if ( sInteractive ) {
- CFStringRef name;
-
- name = KEXTModuleGetProperty(mod, CFSTR(kBundleIDKey));
- if ( name ) {
- CFStringRef message;
-
- message = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Load module '%@'"), name);
- boolval = Prompt(message, true);
- CFRelease(message);
- }
- }
-
- if ( boolval ) {
- error = KEXTManagerLoadModule(manager, mod);
- if ( error != kKEXTReturnSuccess ) {
- KEXTError(error, CFSTR("Error loading module"));
- *(KEXTReturn *)context = error;
- }
- }
-}
-
-static KEXTReturn LoadAllModules(KEXTBundleRef bundle)
-{
- CFArrayRef modules;
- CFRange range;
- KEXTReturn error;
-
- if ( !bundle ) {
- return kKEXTReturnBadArgument;
- }
-
- modules = KEXTManagerCopyModulesForBundle(manager, bundle);
- if ( !modules ) {
- return kKEXTReturnModuleNotFound;
- }
-
- error = kKEXTReturnSuccess;
- range = CFRangeMake(0, CFArrayGetCount(modules));
- CFArrayApplyFunction(modules, range, (CFArrayApplierFunction)ArrayLoadMods, &error);
-
- CFRelease(modules);
-
- return error;
-}
-
-static KEXTReturn LoadAllPersonalities(KEXTBundleRef bundle)
-{
- CFArrayRef array;
- CFArrayRef configs;
- CFMutableArrayRef toLoad;
- CFMutableArrayRef modules;
- CFRange range;
- KEXTReturn error;
- void * context[2];
-
- error = kKEXTReturnSuccess;
-
- // Get the configurations associated with this bundle.
- configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
-
- // Get the personality entities associated with
- // this particular bundle. We use these keys to aquire\
- // personality entities from the database.
- array = KEXTManagerCopyPersonalitiesForBundle(manager, bundle);
-
- if ( !array && !configs ) {
- return kKEXTReturnPersonalityNotFound;
- }
-
- // This is the list of personalities and configurations to load.
- toLoad = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- modules = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-
- if ( configs ) {
- range = CFRangeMake(0, CFArrayGetCount(configs));
- CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)PromptForLoading, toLoad);
- CFRelease(configs);
- }
-
- if ( array ) {
- range = CFRangeMake(0, CFArrayGetCount(array));
- CFArrayApplyFunction(array, range, (CFArrayApplierFunction)PromptForLoading, toLoad);
- CFRelease(array);
- }
-
- context[0] = modules;
- context[1] = &error;
-
- range = CFRangeMake(0, CFArrayGetCount(toLoad));
- CFArrayApplyFunction(toLoad, range, (CFArrayApplierFunction)ArrayGetModuleList, context);
-
- if ( error != kKEXTReturnSuccess ) {
- CFRelease(toLoad);
- CFRelease(modules);
- return error;
- }
-
- // Load all the modules.
- sInteractive = false;
- range = CFRangeMake(0, CFArrayGetCount(modules));
- CFArrayApplyFunction(modules, range, (CFArrayApplierFunction)ArrayLoadMods, &error);
- sInteractive = true;
-
- if ( error != kKEXTReturnSuccess ) {
- CFRelease(toLoad);
- CFRelease(modules);
- return error;
- }
-
- // We need to send all personalities together.
- error = KEXTManagerLoadPersonalities(manager, toLoad);
- CFRelease(toLoad);
- CFRelease(modules);
-
- return error;
-}
-
-int main (int argc, const char *argv[])
-{
- int c;
-
- CFMutableArrayRef libList;
- CFURLRef abs;
- CFStringRef defaultLibDir = NULL;
- CFStringRef path;
- CFStringRef name;
- KEXTBundleRef bundle;
- KEXTReturn error;
-
- sCmdName = argv[0];
-
- name = NULL;
- defaultLibDir = CFSTR(kDefaultSearchPath);
- libList = CFArrayCreateMutable
- (kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if (!libList) {
- fprintf(stderr, "%s: Not enough memory to run\n", sCmdName);
- exit(EX_SOFTWARE);
- }
-
- while ( (c = getopt(argc, (char **)argv, "eihvxp:L:")) != -1 ) {
- switch ( c ) {
- case 'e':
- defaultLibDir = NULL;
- break;
-
- case 'v':
- sVerbose = true;
- break;
-
- case 'x':
- sSafeBoot = true;
- break;
-
- case 'i':
- sInteractive = true;
- break;
-
- case 'h':
- usage(true);
-
- case 'L':
- if ( !optarg )
- usage(false);
- else if (strlen(optarg)) {
- path = CFStringCreateWithCString
- (kCFAllocatorDefault, optarg, kCFStringEncodingASCII);
- CFArrayAppendValue(libList, path);
- CFRelease(path);
- }
-
- case 'p':
- if ( !optarg )
- usage(false);
- else
- name = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingASCII);
- break;
-
- default:
- usage(false);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc < 1)
- usage(false);
-
- if (defaultLibDir)
- CFArrayInsertValueAtIndex(libList, 0, defaultLibDir);
-
- path = CFStringCreateWithCString
- (kCFAllocatorDefault, argv[argc - 1], kCFStringEncodingASCII);
- abs = URLCreateAbsoluteWithPath(path);
- CFRelease(path);
-
- if ( !abs ) {
- fprintf(stderr, "Invalid path: %s.\n", argv[argc - 1]);
- CFRelease(abs);
- exit(-1);
- }
-
- if ( sVerbose ) {
- fprintf(stderr, "Examining: %s\n", argv[argc - 1]);
- }
-
- sAuthenticateAll = false;
- if ( !InitManager(libList) ) {
- fprintf(stderr, "Error initializing KEXT Manager.\n");
- exit(-1);
- }
-
- // Don't authenticate the target bundle, this
- // is just a convenience for developers.
- sAuthenticateAll = true;
-
- // Add the bundle to the database.
- error = KEXTManagerAddBundle(manager, abs);
- if ( error != kKEXTReturnSuccess ) {
- fprintf(stderr, "Error (%d) adding bundle to database.\n", error);
- exit(1);
- }
- // Re-enable the authentication.
- sAuthenticateAll = false;
- // Now, get the bundle entity from the database,
- // this is the handle we use for accessing bundle resources.
- bundle = KEXTManagerGetBundleWithURL(manager, abs);
- if ( !bundle ) {
- fprintf(stderr, "Bundle not found in database.\n");
- exit(EX_DATAERR);
- }
-
- // If no name was given, then assume all personalities should be loaded.
- error = LoadAllPersonalities(bundle);
- if ( error != kKEXTReturnSuccess ) {
- // No personalities are found, then this is probably
- // a kmod bundle. Try loading just the modules.
- if ( error == kKEXTReturnPersonalityNotFound ) {
- // XXX -- Attempt to load modules.
- LoadAllModules(bundle);
- }
- }
-
- if ( manager ) {
- KEXTManagerRelease(manager);
- }
-
- if ( sVerbose ) {
- printf("Done.\n");
- }
-
- return 0; // ...and make main fit the ANSI spec.
-}
+++ /dev/null
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kextunload
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-CFILES = kextunload_main.c
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kextunload.8
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /sbin
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-FRAMEWORKS = -framework CoreFoundation -framework IOKit
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-MAN_PAGE = kextunload.8
-MAN_PATH = /usr/share/man/man8
-
-after_install::
- -mkdir -p ${DSTROOT}$(MAN_PATH)
- -rm -f ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
- cp $(MAN_PAGE) ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
- chmod og-w ${DSTROOT}$(MAN_PATH)/$(MAN_PAGE)
-
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = (CoreFoundation.framework, IOKit.framework);
- OTHER_LINKED = (kextunload_main.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kextunload.8);
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_INSTALLDIR = /sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kextunload;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-.\"
-.\"
-.Dd July 5, 2000
-.Dt kextunload 8
-.Os Apple Computer, Inc.
-.Sh NAME
-.Nm kextunload
-.Nd terminates classes, unloads modules associated with a kernel extension
-.Sh SYNOPSIS
-.Nm kextunload
-.Op Fl c Ar classname
-.Op Fl m Ar modulename
-.Op Fl h
-.Op Ar kextbundle
-.Sh DESCRIPTION
-The
-.Nm
-utility terminates classes and unloads the module files contained within
-.Ar kextbundle
-or with a given name. Modules and classes in the kernel must be written correctly to handle the termination and unload process for this to be successful.
-.Pp
-The following options are available:
-.Bl -tag -width indent
-.It Fl h
-Provide quick help.
-.It Fl m
-Terminate the classes found in the module name given, and unload the module.
-.It Fl c
-Terminate the classes in the kernel with the given name.
-.El
-.Sh FILES
-.Bl -tag -width /modules -compact
-.Ar kextbundle
-directory containing loadable kernel modules.
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success or with a nonzero status if an error occurs.
-.Sh SEE ALSO
-.Xr kextload 8 ,
-.Xr kmodload 8 ,
-.Xr kmodstat 8 ,
-.Xr kmodunload 8
+++ /dev/null
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOKitServer.h>
-#include <IOKit/IOCFSerialize.h>
-#include <mach/mach_types.h>
-
-#include <IOKit/kext/KEXTManager.h>
-
-static Boolean sVerbose = false;
-static Boolean sAuthenticateAll = false;
-
-static KEXTManagerRef manager = NULL;
-static const char * sArgv0;
-static mach_port_t sMasterPort;
-
-#define kBundleIDKey "CFBundleIdentifier"
-
-
-#if 0
-// never were used
-#define kModuleKey "Module"
-#define kModulesKey "Modules"
-#define kModuleFileKey "File"
-#define kPersonalityKey "Personality"
-#define kPersonalitiesKey "Personalities"
-#define kNameKey "Name"
-#define kVendorKey "Vendor"
-#define kVersionKey "Version"
-#define kRequiresKey "Requires"
-#define kModuleAliasesKey "Aliases"
-#endif 0
-
-
-#define kDefaultSearchPath "/System/Library/Extensions"
-
-// These don't seem to be used
-#if 0
-#define kInfoMacOS "Info-macos"
-#define kInfoMacOSType "xml"
-#endif 0
-
-#define defaultPath CFSTR(kDefaultSearchPath)
-
-
-static void usage(Boolean help)
-{
- printf("Usage: %s [-h] [-m modulename] [-c classname] [kextpath]\n", sArgv0);
- exit(-1);
-}
-
-
-// Override the default authentication scheme so we can load
-// kext not owned by root into the kernel.
-static KEXTReturn authenticate(CFURLRef url, void * context)
-{
- if ( !sAuthenticateAll ) {
- KEXTReturn ret;
-
- ret = KEXTManagerAuthenticateURL(url);
- if ( ret != kKEXTReturnSuccess ) {
- if ( sVerbose ) {
- CFURLRef absUrl;
- CFStringRef message;
- CFStringRef path;
-
- absUrl = CFURLCopyAbsoluteURL(url);
- path = CFURLGetString(absUrl);
-
- message = CFStringCreateWithFormat(
- kCFAllocatorDefault,
- NULL,
- CFSTR("Error (%) Authentication failed: %@"),
- ret,
- path);
-
- CFShow(message);
- CFRelease(message);
- CFRelease(absUrl);
- }
- return ret;
- }
- }
-
- return kKEXTReturnSuccess;
-}
-
-// Initialize the KEXTManager.
-static Boolean InitManager(void)
-{
- CFURLRef url;
- KEXTReturn error;
- KEXTManagerBundleLoadingCallbacks bCallback = {
- 0, authenticate, NULL, NULL, NULL, NULL, NULL,
- };
- KEXTManagerModuleLoadingCallbacks mCallbacks = {
- 0, NULL, NULL, NULL, NULL, NULL,
- };
-
- // Give the manager the default path to the Extensions folder.
- // This is needed for dependency matching.
- url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, defaultPath, kCFURLPOSIXPathStyle, true);
-
- // Create the manager database.
- manager = KEXTManagerCreate(&bCallback, &mCallbacks, NULL, NULL, NULL, NULL, NULL, false, &error);
- if ( !manager ) {
- printf("Manager not created.\n");
- return false;
- }
-
- // Now scan in all the bundles in the extensions directory.
- if ( (error = KEXTManagerScanPath(manager, url)) != kKEXTReturnSuccess ) {
- if ( sVerbose ) {
- KEXTError(error, CFSTR("Error scanning path"));
- }
- return false;
- };
-
- return true;
-}
-
-
-static KEXTReturn KEXTUnloadAllModules(KEXTBundleRef bundle)
-{
- CFArrayRef modules;
- kern_return_t kr;
- KEXTModuleRef mod;
- char buf[256];
- unsigned int i;
- CFIndex count;
-
- if ( !bundle ) {
- return kKEXTReturnBadArgument;
- }
-
- modules = KEXTManagerCopyModulesForBundle(manager, bundle);
- if ( !modules ) {
- return kKEXTReturnModuleNotFound;
- }
-
- for( i = 0, count = CFArrayGetCount(modules); i < count; i++) {
- CFStringRef name;
-
- mod = (KEXTModuleRef) CFArrayGetValueAtIndex( modules, i);
- name = KEXTModuleGetProperty( mod, CFSTR(kBundleIDKey));
-
- if( CFStringGetCString( name, buf, sizeof(buf), kCFStringEncodingMacRoman)) {
-
- kr = IOCatalogueTerminate( sMasterPort, kIOCatalogModuleUnload, buf );
- printf("IOCatalogueTerminate(Module %s) [%x]\n", buf, kr);
- }
- }
-
- CFRelease(modules);
-
- return kKEXTReturnSuccess;
-}
-
-KEXTReturn KEXTUnload( const char * cPath )
-{
- CFURLRef url;
- CFURLRef abs;
- CFStringRef path;
- KEXTBundleRef bundle;
- KEXTReturn error;
-
- path = CFStringCreateWithCString(kCFAllocatorDefault, cPath, kCFStringEncodingASCII);
- url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, true);
- CFRelease(path);
-
- abs = CFURLCopyAbsoluteURL(url);
- CFRelease(url);
-
- if ( !abs ) {
- printf("Invalid path: %s.\n", cPath);
- CFRelease(abs);
- exit(-1);
- }
-
- sAuthenticateAll = false;
- if ( !InitManager() ) {
- printf("Error initializing KEXT Manager.\n");
- exit(-1);
- }
-
- // Don't authenticate the target bundle, this
- // is just a convenience for developers.
- sAuthenticateAll = true;
-
- // Add the bundle to the database.
- error = KEXTManagerAddBundle(manager, abs);
- if ( error != kKEXTReturnSuccess ) {
- printf("Error (%d) adding bundle to database.\n", error);
- exit(1);
- }
- // Re-enable the authentication.
- sAuthenticateAll = false;
- // Now, get the bundle entity from the database,
- // this is the handle we use for accessing bundle resources.
- bundle = KEXTManagerGetBundleWithURL(manager, abs);
- if ( !bundle ) {
- printf("Bundle not found in database.\n");
- exit(1);
- }
-
- error = KEXTUnloadAllModules(bundle);
-
- if ( manager ) {
- KEXTManagerRelease(manager);
- }
-
- return( error );
-}
-
-int main (int argc, const char *argv[])
-{
- int c;
- const char * name = NULL;
- int command = 0;
- KEXTReturn error;
- kern_return_t kr;
-
- // Obtain the I/O Kit communication handle.
- kr = IOMasterPort(bootstrap_port, &sMasterPort);
- if( kr != KERN_SUCCESS)
- exit(-1);
-
- sArgv0 = argv[0];
-
- if (argc < 2)
- usage(false);
-
- while ( (c = getopt(argc, (char **)argv, "hm:c:")) != -1 ) {
- switch ( c ) {
-
- case 'h':
- usage(true);
-
- case 'c':
- command = kIOCatalogServiceTerminate;
- if ( !optarg )
- usage(false);
- else
- name = optarg;
- break;
-
- case 'm':
- command = kIOCatalogModuleUnload;
- if ( !optarg )
- usage(false);
- else
- name = optarg;
- break;
-
- default:
- usage(false);
- }
- }
-
- argc -= optind;
- argv += optind;
- if (argc >= 1) {
- name = argv[argc - 1];
- error = KEXTUnload( name );
- }
-
- if( command >= kIOCatalogModuleUnload) {
- kr = IOCatalogueTerminate( sMasterPort, command, (char *) name );
- printf("IOCatalogueTerminate(%s %s) [%x]\n",
- (command == kIOCatalogModuleUnload) ? "Module" : "Class",
- name, kr);
- }
- printf("done.\n");
-
- return 0; // ...and make main fit the ANSI spec.
-}
+++ /dev/null
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kmodload
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-HFILES = kld_patch.h
-
-CFILES = kld_patch.c kmodload.c
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kmodload.8\
- kmodsyms.8
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /sbin
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS = -lkld
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-###############################################################################
-# Makefile.postamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile, which is imported after all other makefiles, to
-# override attributes for a project's Makefile environment. This allows you
-# to take advantage of the environment set up by the other Makefiles.
-# You can also define custom rules at the end of this file.
-#
-###############################################################################
-#
-# These variables are exported by the standard makefiles and can be
-# used in any customizations you make. They are *outputs* of
-# the Makefiles and should be used, not set.
-#
-# PRODUCTS: products to install. All of these products will be placed in
-# the directory $(DSTROOT)$(INSTALLDIR)
-# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
-# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
-# OFILE_DIR: Directory into which .o object files are generated.
-# DERIVED_SRC_DIR: Directory used for all other derived files
-#
-# ALL_CFLAGS: flags to pass when compiling .c files
-# ALL_MFLAGS: flags to pass when compiling .m files
-# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
-# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
-# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
-# ALL_LDFLAGS: flags to pass when linking object files
-# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
-# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
-# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
-# ALL_YFLAGS: flags to pass when processing .y (yacc) files
-# ALL_LFLAGS: flags to pass when processing .l (lex) files
-#
-# NAME: name of application, bundle, subproject, palette, etc.
-# LANGUAGES: langages in which the project is written (default "English")
-# English_RESOURCES: localized resources (e.g. nib's, images) of project
-# GLOBAL_RESOURCES: non-localized resources of project
-#
-# SRCROOT: base directory in which to place the new source files
-# SRCPATH: relative path from SRCROOT to present subdirectory
-#
-# INSTALLDIR: Directory the product will be installed into by 'install' target
-# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-#
-# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
-#
-###############################################################################
-
-# Some compiler flags can be overridden here for certain build situations.
-#
-# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
-# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
-# to -g)
-# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
-# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
-# to -O)
-# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
-# to -pg -DPROFILE)
-# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
-# the include path (defaults to -I.)
-# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
-# passed to ld/libtool (defaults to nothing)
-
-
-# Library and Framework projects only:
-# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
-# against the framework will run against the correct version even if
-# the current version of the framework changes. You may override this
-# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
-# development cycle, but be sure to restore it before installing.
-
-
-# Ownership and permissions of files installed by 'install' target
-
-#INSTALL_AS_USER = root
- # User/group ownership
-#INSTALL_AS_GROUP = wheel
- # (probably want to set both of these)
-#INSTALL_PERMISSIONS =
- # If set, 'install' chmod's executable to this
-
-
-# Options to strip. Note: -S strips debugging symbols (executables can be stripped
-# down further with -x or, if they load no bundles, with no options at all).
-
-#STRIPFLAGS = -S
-
-
-#########################################################################
-# Put rules to extend the behavior of the standard Makefiles here. Include them in
-# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
-#
-# You should avoid redefining things like "install" or "app", as they are
-# owned by the top-level Makefile API and no context has been set up for where
-# derived files should go.
-#
-
-after_install::
- -mkdir -p ${DSTROOT}/usr/share/man/man8
- -rm -f ${DSTROOT}/usr/share/man/man8/kmodload.8
- cp kmodload.8 ${DSTROOT}/usr/share/man/man8/kmodload.8
- chmod og-w ${DSTROOT}/usr/share/man/man8/kmodload.8
- -rm -f ${DSTROOT}/usr/share/man/man8/kmodsyms.8
- cp kmodsyms.8 ${DSTROOT}/usr/share/man/man8/kmodsyms.8
- chmod og-w ${DSTROOT}/usr/share/man/man8/kmodsyms.8
- $(LN) -f $(INSTALLED_PRODUCTS) $(DSTROOT)/usr/sbin/kmodsyms
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = ();
- HEADERSEARCH = ();
- H_FILES = (kld_patch.h);
- OTHER_LIBS = (kld);
- OTHER_LINKED = (kld_patch.c, kmodload.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kmodload.8, kmodsyms.8);
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
- NEXTSTEP_INSTALLDIR = /sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kmodload;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-/*
- * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * History:
- * 2001-05-30 gvdl Initial implementation of the vtable patcher.
- */
-// 45678901234567890123456789012345678901234567890123456789012345678901234567890
-
-#include <mach-o/fat.h>
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-#include <mach-o/reloc.h>
-
-#if KERNEL
-
-#include <stdarg.h>
-#include <string.h>
-
-#include <sys/systm.h>
-
-#include <libkern/OSTypes.h>
-
-#include <libsa/stdlib.h>
-#include <libsa/mach/mach.h>
-
-#include "mach_loader.h"
-
-#include <vm/vm_kern.h>
-
-enum { false = 0, true = 1 };
-
-#define vm_page_size page_size
-
-extern load_return_t fatfile_getarch(
- void * vp, // normally a (struct vnode *)
- vm_offset_t data_ptr,
- struct fat_arch * archret);
-
-#else /* !KERNEL */
-#include <unistd.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/errno.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <mach-o/arch.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#endif /* KERNEL */
-
-#include "kld_patch.h"
-
-#if 0
-static __inline__ void DIE(void) { IODelay(2000000000); }
-
-#define LOG_DELAY() IODelay(200000)
-#define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
-#else
-
-#define DIE()
-#define LOG_DELAY()
-#define DEBUG_LOG(x)
-
-#endif
-
-// OSObject symbol prefixes and suffixes
-#define kVTablePrefix "___vt"
-#define kReservedPrefix "__RESERVED"
-#define kSuperClassSuffix ".superClass"
-#define kGMetaSuffix ".gMetaClass"
-#define kLinkEditSegName SEG_LINKEDIT
-
-// GCC 2.95 drops 2 leading constants in the vtable
-#define kVTablePreambleLen 2
-
-// Last address that I'm willing to try find vm in
-#define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
-
-// Size in bytes that Data Ref object's get increased in size
-// Must be a power of 2
-#define kDataCapacityIncrement 128
-
-// My usual set of helper macros. I personally find these macros
-// easier to read in the code rather than an explicit error condition
-// check. If I don't make it easy then I may get lazy ond not check
-// everything. I'm sorry if you find this code harder to read.
-
-// break_if will evaluate the expression and if it is true
-// then it will print the msg, which is enclosed in parens
-// and then break. Usually used in loops are do { } while (0)
-#define break_if(expr, msg) \
- if (expr) { \
- errprintf msg; \
- break; \
- }
-
-// return_if will evaluate expr and if true it will log the
-// msg, which is enclosed in parens, and then it will return
-// with the return code of ret.
-#define return_if(expr, ret, msg) do { \
- if (expr) { \
- errprintf msg; \
- return ret; \
- } \
-} while (0)
-
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif /* MIN */
-#ifndef MAX
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#endif /* MAX */
-
-typedef struct Data {
- unsigned long fLength, fCapacity;
- unsigned char *fData;
-} Data, *DataRef;
-
-struct sectionRecord {
- const struct section *fSection;
- DataRef fRelocCache;
-};
-
-enum patchState {
- kSymbolIdentical,
- kSymbolLocal,
- kSymbolPadUpdate,
- kSymbolSuperUpdate,
- kSymbolMismatch
-};
-
-struct patchRecord {
- struct nlist *fSymbol;
- enum patchState fType;
-};
-
-struct relocRecord {
- void *fValue;
- const struct nlist *fSymbol;
- struct relocation_info *fRInfo;
- void *reserved;
-};
-
-struct metaClassRecord {
- char *fSuperName;
- struct fileRecord *fFile;
- const struct nlist *fVTableSym;
- struct patchRecord *fPatchedVTable;
- char fClassName[1];
-};
-
-struct fileRecord {
- size_t fMapSize, fMachOSize;
- const char *fPath;
- unsigned char *fMap, *fMachO, *fPadEnd;
- DataRef fClassList;
- DataRef fSectData;
- DataRef fNewSymbols, fNewStrings;
- struct symtab_command *fSymtab;
- struct sectionRecord *fSections;
- char *fStringBase;
- struct nlist *fSymbolBase;
- const struct nlist *fLocalSyms;
- unsigned int fNSects;
- int fNLocal;
- int fNewStringsLen;
- Boolean fIsKernel, fNoKernelExecutable, fIsKmem;
- Boolean fImageDirty, fSymbolsDirty;
-};
-
-static DataRef sFilesTable;
-static struct fileRecord *sKernelFile;
-
-static DataRef sMergedFiles;
-static DataRef sMergeMetaClasses;
-static Boolean sMergedKernel;
-
-static void errprintf(const char *fmt, ...)
-{
- extern void kld_error_vprintf(const char *format, va_list ap);
-
- va_list ap;
-
- va_start(ap, fmt);
- kld_error_vprintf(fmt, ap);
- va_end(ap);
-
-DIE();
-}
-
-static __inline__ unsigned long DataGetLength(DataRef data)
-{
- return data->fLength;
-}
-
-static __inline__ unsigned char *DataGetPtr(DataRef data)
-{
- return data->fData;
-}
-
-
-static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr)
-{
- unsigned char *addr = vAddr;
-
- return (data->fData <= addr) && (addr < data->fData + data->fLength);
-}
-
-static __inline__ Boolean DataAddLength(DataRef data, unsigned long length)
-{
- static Boolean DataSetLength(DataRef data, unsigned long length);
- return DataSetLength(data, data->fLength + length);
-}
-
-static __inline__ Boolean
-DataAppendBytes(DataRef data, const void *addr, unsigned int len)
-{
- unsigned long size = DataGetLength(data);
-
- if (!DataAddLength(data, len))
- return false;
-
- bcopy(addr, DataGetPtr(data) + size, len);
- return true;
-}
-
-static __inline__ Boolean DataAppendData(DataRef dst, DataRef src)
-{
- return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src));
-}
-
-static Boolean DataSetLength(DataRef data, unsigned long length)
-{
- // Don't bother to ever shrink a data object.
- if (length > data->fCapacity) {
- unsigned char *newData;
- unsigned long newCapacity;
-
- newCapacity = length + kDataCapacityIncrement - 1;
- newCapacity &= ~(kDataCapacityIncrement - 1);
- newData = (unsigned char *) realloc(data->fData, newCapacity);
- if (!newData)
- return false;
-
- bzero(newData + data->fCapacity, newCapacity - data->fCapacity);
- data->fData = newData;
- data->fCapacity = newCapacity;
- }
-
- data->fLength = length;
- return true;
-}
-
-static DataRef DataCreate(unsigned long length)
-{
- DataRef data = (DataRef) malloc(sizeof(Data));
-
- if (data) {
- if (!length)
- data->fCapacity = kDataCapacityIncrement;
- else {
- data->fCapacity = length + kDataCapacityIncrement - 1;
- data->fCapacity &= ~(kDataCapacityIncrement - 1);
- }
-
- data->fData = (unsigned char *) malloc(data->fCapacity);
- if (!data->fData) {
- free(data);
- return NULL;
- }
-
- bzero(data->fData, data->fCapacity);
- data->fLength = length;
- }
- return data;
-}
-
-static void DataRelease(DataRef data)
-{
- if (data) {
- if (data->fData)
- free(data->fData);
- data->fData = 0;
- free(data);
- }
-}
-
-static const char *
-symbolname(const struct fileRecord *file, const struct nlist *sym)
-{
- unsigned long strsize;
- long strx = sym->n_un.n_strx;
-
- if (strx >= 0)
- return file->fStringBase + strx;
-
- strsize = file->fSymtab->strsize;
- strx = -strx;
- if (strx < strsize)
- return file->fStringBase + strx;
-
- strx -= strsize;
- return (char *) DataGetPtr(file->fNewStrings) + strx;
-}
-
-static struct fileRecord *getFile(const char *path)
-{
- if (sFilesTable) {
- int i, nfiles;
- struct fileRecord **files;
-
- // Check to see if we have already merged this file
- nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
- files = (struct fileRecord **) DataGetPtr(sFilesTable);
- for (i = 0; i < nfiles; i++) {
- if (!strcmp(path, files[i]->fPath))
- return files[i];
- }
- }
-
- return NULL;
-}
-
-static struct fileRecord * addFile(struct fileRecord *file)
-{
- struct fileRecord *newFile;
-
- if (!sFilesTable) {
- sFilesTable = DataCreate(0);
- if (!sFilesTable)
- return NULL;
- }
-
- newFile = (struct fileRecord *) malloc(sizeof(struct fileRecord));
- if (!newFile)
- return NULL;
-
- if (!DataAppendBytes(sFilesTable, &newFile, sizeof(newFile))) {
- free(newFile);
- return NULL;
- }
-
- bcopy(file, newFile, sizeof(struct fileRecord));
- return newFile;
-}
-
-// @@@ gvdl: need to clean up the sMergeMetaClasses
-// @@@ gvdl: I had better fix the object file up again
-static void removeFile(struct fileRecord *file)
-{
- if (file->fClassList) {
- DataRelease(file->fClassList);
- file->fClassList = 0;
- }
-
- if (file->fSectData) {
- struct sectionRecord *section;
- unsigned int i, nsect;
-
- nsect = file->fNSects;
- section = file->fSections;
- for (i = 0; i < nsect; i++, section++) {
- if (section->fRelocCache) {
- DataRelease(section->fRelocCache);
- section->fRelocCache = 0;
- }
- }
-
- DataRelease(file->fSectData);
- file->fSectData = 0;
- file->fSections = 0;
- file->fNSects = 0;
- }
-
- if (file->fMap) {
-#if KERNEL
- if (file->fIsKmem)
- kmem_free(kernel_map, (vm_address_t) file->fMap, file->fMapSize);
-#else /* !KERNEL */
- if (file->fPadEnd) {
- vm_address_t padVM;
- vm_size_t padSize;
-
- padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
- padSize = (vm_size_t) ((vm_address_t) file->fPadEnd - padVM);
- (void) vm_deallocate(mach_task_self(), padVM, padSize);
- file->fPadEnd = 0;
- }
-
- (void) munmap((caddr_t) file->fMap, file->fMapSize);
-#endif /* !KERNEL */
- file->fMap = 0;
- }
-
- file->fPath = 0;
-}
-
-#if !KERNEL
-static Boolean
-mapObjectFile(struct fileRecord *file)
-{
- Boolean result = false;
- static unsigned char *sFileMapBaseAddr;
-
- int fd = 0;
-
- if (!sFileMapBaseAddr) {
- kern_return_t ret;
- vm_address_t probeAddr;
-
- // If we don't already have a base addr find any random chunk
- // of 32 meg of VM and to use the 16 meg boundrary as a base.
- ret = vm_allocate(mach_task_self(), &probeAddr,
- 32 * 1024 * 1024, VM_FLAGS_ANYWHERE);
- return_if(KERN_SUCCESS != ret, false,
- ("Unable to allocate base memory %s\n", mach_error_string(ret)));
- (void) vm_deallocate(mach_task_self(), probeAddr, 32 * 1024 * 1024);
-
- // Now round to the next 16 Meg boundrary
- probeAddr = (probeAddr + (16 * 1024 * 1024 - 1))
- & ~(16 * 1024 * 1024 - 1);
- sFileMapBaseAddr = (unsigned char *) probeAddr;
- }
-
- fd = open(file->fPath, O_RDONLY, 0);
- return_if(fd == -1, false, ("Can't open %s for reading - %s\n",
- file->fPath, strerror(errno)));
-
- do {
- kern_return_t ret;
- struct stat sb;
- int retaddr = -1;
-
- break_if(fstat(fd, &sb) == -1,
- ("Can't stat %s - %s\n", file->fPath, strerror(errno)));
-
- file->fMapSize = sb.st_size;
- file->fMap = sFileMapBaseAddr;
- ret = KERN_SUCCESS;
- while (file->fMap < kTopAddr) {
- vm_address_t padVM;
- vm_address_t padVMEnd;
- vm_size_t padSize;
-
- padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
- retaddr = (int) mmap(file->fMap, file->fMapSize,
- PROT_READ|PROT_WRITE,
- MAP_FIXED|MAP_FILE|MAP_PRIVATE,
- fd, 0);
- if (-1 == retaddr) {
- break_if(ENOMEM != errno,
- ("mmap failed %d - %s\n", errno, strerror(errno)));
-
- file->fMap = (unsigned char *) padVM;
- continue;
- }
-
-
- // Round up padVM to the next page after the file and assign at
- // least another fMapSize more room rounded up to the next page
- // boundary.
- padVMEnd = round_page(padVM + file->fMapSize);
- padSize = padVMEnd - padVM;
- ret = vm_allocate(
- mach_task_self(), &padVM, padSize, VM_FLAGS_FIXED);
- if (KERN_SUCCESS == ret) {
- file->fPadEnd = (unsigned char *) padVMEnd;
- break;
- }
- else {
- munmap(file->fMap, file->fMapSize);
- break_if(KERN_INVALID_ADDRESS != ret,
- ("Unable to allocate pad vm for %s - %s\n",
- file->fPath, mach_error_string(ret)));
-
- file->fMap = (unsigned char *) padVMEnd;
- continue; // try again wherever the vm system wants
- }
- }
-
- if (-1 == retaddr || KERN_SUCCESS != ret)
- break;
-
- break_if(file->fMap >= kTopAddr,
- ("Unable to map memory %s\n", file->fPath));
-
- sFileMapBaseAddr = file->fPadEnd;
- result = true;
- } while(0);
-
- close(fd);
- return result;
-}
-#endif /* !KERNEL */
-
-static Boolean findBestArch(struct fileRecord *file)
-{
- unsigned long magic;
- struct fat_header *fat;
-
-
- file->fMachOSize = file->fMapSize;
- file->fMachO = file->fMap;
- magic = ((const struct mach_header *) file->fMachO)->magic;
- fat = (struct fat_header *) file->fMachO;
-
- // Try to figure out what type of file this is
- return_if(file->fMapSize < sizeof(unsigned long), false,
- ("%s isn't a valid object file - no magic\n", file->fPath));
-
-#if KERNEL
-
- // CIGAM is byte-swapped MAGIC
- if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
-
- load_return_t load_return;
- struct fat_arch fatinfo;
-
- load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo);
- return_if(load_return != LOAD_SUCCESS, false,
- ("Extension \"%s\": has no code for this computer\n", file->fPath));
-
- file->fMachO = file->fMap + fatinfo.offset;
- file->fMachOSize = fatinfo.size;
- magic = ((const struct mach_header *) file->fMachO)->magic;
- }
-
-#else /* !KERNEL */
-
- // Do we need to in-place swap the endianness of the fat header?
- if (magic == FAT_CIGAM) {
- unsigned long i;
- struct fat_arch *arch;
-
- fat->nfat_arch = NXSwapBigLongToHost(fat->nfat_arch);
- return_if(file->fMapSize < sizeof(struct fat_header)
- + fat->nfat_arch * sizeof(struct fat_arch),
- false, ("%s is too fat\n", file->fPath));
-
- arch = (struct fat_arch *) &fat[1];
- for (i = 0; i < fat->nfat_arch; i++) {
- arch[i].cputype = NXSwapBigLongToHost(arch[i].cputype);
- arch[i].cpusubtype = NXSwapBigLongToHost(arch[i].cpusubtype);
- arch[i].offset = NXSwapBigLongToHost(arch[i].offset);
- arch[i].size = NXSwapBigLongToHost(arch[i].size);
- arch[i].align = NXSwapBigLongToHost(arch[i].align);
- }
-
- magic = NXSwapBigLongToHost(fat->magic);
- }
-
- // Now see if we can find any valid architectures
- if (magic == FAT_MAGIC) {
- const NXArchInfo *myArch;
- unsigned long fatsize;
- struct fat_arch *arch;
-
- fatsize = sizeof(struct fat_header)
- + fat->nfat_arch * sizeof(struct fat_arch);
- return_if(file->fMapSize < fatsize,
- false, ("%s isn't a valid fat file\n", file->fPath));
-
- myArch = NXGetLocalArchInfo();
- arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
- (struct fat_arch *) &fat[1], fat->nfat_arch);
- return_if(!arch,
- false, ("%s hasn't got arch for %s\n", file->fPath, myArch->name));
- return_if(arch->offset + arch->size > file->fMapSize,
- false, ("%s's %s arch is incomplete\n", file->fPath, myArch->name));
- file->fMachO = file->fMap + arch->offset;
- file->fMachOSize = arch->size;
- magic = ((const struct mach_header *) file->fMachO)->magic;
- }
-
-#endif /* KERNEL */
-
- return_if(magic != MH_MAGIC,
- false, ("%s isn't a valid mach-o\n", file->fPath));
-
- return true;
-}
-
-static Boolean
-parseSegments(struct fileRecord *file, struct segment_command *seg)
-{
- struct sectionRecord *sections;
- int i, nsects = seg->nsects;
- const struct segmentMap {
- struct segment_command seg;
- const struct section sect[1];
- } *segMap;
-
- if (!nsects) {
-#if KERNEL
- // We don't need to look for the LinkEdit segment unless
- // we are running in the kernel environment.
- if (!strcmp(kLinkEditSegName, seg->segname)) {
- // Grab symbol table from linkedit we will need this later
- file->fSymbolBase = (void *) seg;
- }
-#endif
-
- return true; // Nothing more to do, so that was easy.
- }
-
- if (!file->fSectData) {
- file->fSectData = DataCreate(0);
- if (!file->fSectData)
- return false;
- }
-
- // Increase length of section DataRef and cache data pointer
- if (!DataAddLength(file->fSectData, nsects * sizeof(struct sectionRecord)))
- return false;
- file->fSections = (struct sectionRecord *) DataGetPtr(file->fSectData);
-
- // Initialise the new sections
- sections = &file->fSections[file->fNSects];
- file->fNSects += nsects;
- for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
- sections[i].fSection = &segMap->sect[i];
-
- return true;
-}
-
-// @@@ gvdl: These functions need to be hashed they are
-// going to be way too slow for production code.
-static const struct nlist *
-findSymbolByAddress(const struct fileRecord *file, void *entry)
-{
- // not quite so dumb linear search of all symbols
- const struct nlist *sym;
- int i, nsyms;
-
- // First try to find the symbol in the most likely place which is the
- // extern symbols
- sym = file->fLocalSyms;
- for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
- if (sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
- return sym;
- }
-
- // Didn't find it in the external symbols so try to local symbols before
- // giving up.
- sym = file->fSymbolBase;
- for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
- if ( (sym->n_type & N_EXT) )
- return NULL;
- if ( sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
- return sym;
- }
-
- return NULL;
-}
-
-struct searchContext {
- const char *fSymname;
- const char *fStrbase;
-};
-
-static int symbolSearch(const void *vKey, const void *vSym)
-{
- const struct searchContext *key = (const struct searchContext *) vKey;
- const struct nlist *sym = (const struct nlist *) vSym;
-
- return strcmp(key->fSymname, key->fStrbase + sym->n_un.n_strx);
-}
-
-static const struct nlist *
-findSymbolByName(struct fileRecord *file, const char *symname)
-{
- struct searchContext context;
-
- context.fSymname = symname;
- context.fStrbase = file->fStringBase;
- return (struct nlist *)
- bsearch(&context,
- file->fLocalSyms, file->fNLocal, sizeof(struct nlist),
- symbolSearch);
-}
-
-static Boolean
-relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec)
-{
- const struct nlist *symbol;
- const struct section *section;
- struct relocRecord *rec;
- struct relocation_info *rinfo;
- unsigned long i;
- unsigned long r_address, r_symbolnum, r_length;
- enum reloc_type_generic r_type;
- UInt8 *sectionBase;
- void **entry;
-
- sectionRec->fRelocCache = DataCreate(
- sectionRec->fSection->nreloc * sizeof(struct relocRecord));
- if (!sectionRec->fRelocCache)
- return false;
-
- section = sectionRec->fSection;
- sectionBase = file->fMachO + section->offset;
-
- rec = (struct relocRecord *) DataGetPtr(sectionRec->fRelocCache);
- rinfo = (struct relocation_info *) (file->fMachO + section->reloff);
- for (i = 0; i < section->nreloc; i++, rec++, rinfo++) {
-
- // Totally uninterested in scattered relocation entries
- if ( (rinfo->r_address & R_SCATTERED) )
- continue;
-
- r_address = rinfo->r_address;
- entry = (void **) (sectionBase + r_address);
-
- /*
- * The r_address field is really an offset into the contents of the
- * section and must reference something inside the section (Note
- * that this is not the case for PPC_RELOC_PAIR entries but this
- * can't be one with the above checks).
- */
- return_if(r_address >= section->size, false,
- ("Invalid relocation entry in %s - not in section\n", file->fPath));
-
- // If we don't have a VANILLA entry or the Vanilla entry isn't
- // a 'long' then ignore the entry and try the next.
- r_type = (enum reloc_type_generic) rinfo->r_type;
- r_length = rinfo->r_length;
- if (r_type != GENERIC_RELOC_VANILLA || r_length != 2)
- continue;
-
- r_symbolnum = rinfo->r_symbolnum;
-
- /*
- * If rinfo->r_extern is set this relocation entry is an external entry
- * else it is a local entry.
- */
- if (rinfo->r_extern) {
- /*
- * This is an external relocation entry.
- * r_symbolnum is an index into the input file's symbol table
- * of the symbol being refered to. The symbol must be
- * undefined to be used in an external relocation entry.
- */
- return_if(r_symbolnum >= file->fSymtab->nsyms, false,
- ("Invalid relocation entry in %s - no symbol\n", file->fPath));
-
- /*
- * If this is an indirect symbol resolve indirection (all chains
- * of indirect symbols have been resolved so that they point at
- * a symbol that is not an indirect symbol).
- */
- symbol = file->fSymbolBase;
- if ((symbol[r_symbolnum].n_type & N_TYPE) == N_INDR)
- r_symbolnum = symbol[r_symbolnum].n_value;
- symbol = &symbol[r_symbolnum];
-
- return_if(symbol->n_type != (N_EXT | N_UNDF), false,
- ("Invalid relocation entry in %s - extern\n", file->fPath));
- }
- else {
- /*
- * If the symbol is not in any section then it can't be a
- * pointer to a local segment and I don't care about it.
- */
- if (r_symbolnum == R_ABS)
- continue;
-
- // Note segment references are offset by 1 from 0.
- return_if(r_symbolnum > file->fNSects, false,
- ("Invalid relocation entry in %s - local\n", file->fPath));
-
- // Find the symbol, if any, that backs this entry
- symbol = findSymbolByAddress(file, *entry);
- }
-
- rec->fValue = *entry; // Save the previous value
- rec->fRInfo = rinfo; // Save a pointer to the reloc
- rec->fSymbol = symbol; // Record the current symbol
-
- *entry = (void *) rec; // Save pointer to record in object image
- }
-
- ((struct fileRecord *) file)->fImageDirty = true;
-
- return true;
-}
-
-static const struct nlist *
-findSymbolRefAtLocation(const struct fileRecord *file,
- struct sectionRecord *sctn, void **loc)
-{
- if (file->fIsKernel) {
- if (*loc)
- return findSymbolByAddress(file, *loc);
- }
- else if (sctn->fRelocCache || relocateSection(file, sctn)) {
- struct relocRecord *reloc = (struct relocRecord *) *loc;
-
- if (DataContainsAddr(sctn->fRelocCache, reloc))
- return reloc->fSymbol;
- }
-
- return NULL;
-}
-
-static Boolean
-addClass(struct fileRecord *file,
- struct metaClassRecord *inClass,
- const char *cname)
-{
- struct metaClassRecord *newClass = NULL;
- struct metaClassRecord **fileClasses = NULL;
- int len;
-
-if (!file->fIsKernel) { // @@@ gvdl:
- DEBUG_LOG(("Adding Class %s\n", cname));
-}
-
- if (!file->fClassList) {
- file->fClassList = DataCreate(0);
- if (!file->fClassList)
- return false;
- }
-
- do {
- // Attempt to allocate all necessary resource first
- len = strlen(cname) + 1
- + (int) (&((struct metaClassRecord *) 0)->fClassName);
- newClass = (struct metaClassRecord *) malloc(len);
- if (!newClass)
- break;
-
- if (!DataAddLength(file->fClassList, sizeof(struct metaClassRecord *)))
- break;
- fileClasses = (struct metaClassRecord **)
- (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList));
-
- // Copy the meta Class structure and string name into newClass
- // and insert object at end of the file->fClassList and sMergeMetaClasses
- *newClass = *inClass;
- strcpy(newClass->fClassName, cname);
- fileClasses[-1] = newClass;
-
- return true;
- } while (0);
-
- if (fileClasses)
- DataAddLength(file->fClassList, -sizeof(struct metaClassRecord *));
-
- if (newClass)
- free(newClass);
-
- return false;
-}
-
-static struct metaClassRecord *getClass(DataRef classList, const char *cname)
-{
- if (classList) {
- int i, nclass;
- struct metaClassRecord **classes, *thisClass;
-
- nclass = DataGetLength(classList) / sizeof(struct metaClassRecord *);
- classes = (struct metaClassRecord **) DataGetPtr(classList);
- for (i = 0; i < nclass; i++) {
- thisClass = classes[i];
- if (!strcmp(thisClass->fClassName, cname))
- return thisClass;
- }
- }
-
- return NULL;
-}
-
-// Add the class 'cname' to the list of known OSObject based classes
-// Note 'sym' is the <cname>.superClass symbol.
-static Boolean
-recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym)
-{
- char *supername = NULL;
- const char *classname = NULL;
- struct metaClassRecord newClass;
- char strbuffer[1024];
-
- // Only do the work actual work to find the super class if we are
- // not currently working on the kernel. The kernel is the end
- // of all superclass chains as by definition the kernel is binary
- // compatible with itself.
- if (!file->fIsKernel) {
- const char *dot;
- const struct nlist *supersym;
- const struct section *section;
- struct sectionRecord *sectionRec;
- unsigned char sectind = sym->n_sect;
- const char *superstr;
- void **location;
-
- // We can't resolve anything that isn't in a real section
- // Note that the sectind is starts at one to make room for the
- // NO_SECT flag but the fNSects field isn't offset so we have a
- // '>' test. Which means this isn't an OSObject based class
- if (sectind == NO_SECT || sectind > file->fNSects)
- return true;
-
- sectionRec = file->fSections + sectind - 1;
- section = sectionRec->fSection;
- location = (void **) ( file->fMachO + section->offset
- + sym->n_value - section->addr );
-
- supersym = findSymbolRefAtLocation(file, sectionRec, location);
- if (!supersym)
- return true; // No superclass symbol then it isn't an OSObject.
-
- // Find string in file and skip leading '_' and find last '.'
- superstr = symbolname(file, supersym) + 1;
- dot = strrchr(superstr, '.');
- if (!dot || strcmp(dot, kGMetaSuffix))
- return true; // Not an OSObject superclass so ignore it.
-
- supername = (char *) malloc(dot - superstr + 1);
- strncpy(supername, superstr, dot - superstr);
- supername[dot - superstr] = '\0';
- }
-
- do {
- break_if(getClass(file->fClassList, cname),
- ("Duplicate class %s in %s\n", cname, file->fPath));
-
- snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname);
- newClass.fVTableSym = findSymbolByName(file, strbuffer);
- break_if(!newClass.fVTableSym,
- ("Can't find vtable %s in %s\n", cname, file->fPath));
-
- newClass.fFile = file;
- newClass.fSuperName = supername;
- newClass.fPatchedVTable = NULL;
-
- // Can't use cname as it may be a stack variable
- // However the vtable's string has the class name as a suffix
- // so why don't we use that rather than mallocing a string.
- classname = symbolname(file, newClass.fVTableSym)
- + sizeof(kVTablePrefix) - 1;
- break_if(!addClass(file, &newClass, classname),
- ("recordClass - no memory?\n"));
-
- return true;
- } while (0);
-
- if (supername)
- free(supername);
-
- return false;
-}
-
-static Boolean getMetaClassGraph(struct fileRecord *file)
-{
- const struct nlist *sym;
- const char *strbase;
- int i, nsyms;
-
- // Search the symbol table for the local symbols that are generated
- // by the metaclass system. There are three metaclass variables
- // that are relevant.
- //
- // <ClassName>.metaClass A pointer to the meta class structure.
- // <ClassName>.superClass A pointer to the super class's meta class.
- // <ClassName>.gMetaClass The meta class structure itself.
- // ___vt<ClassName> The VTable for the class <ClassName>.
- //
- // In this code I'm going to search for any symbols that
- // ends in kSuperClassSuffix as this indicates this class is a conforming
- // OSObject subclass and will need to be patched, and it also
- // contains a pointer to the super class's meta class structure.
- strbase = file->fStringBase;
- sym = file->fLocalSyms;
- for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
- const char *symname;
- const char *dot;
- char classname[1024];
- unsigned char n_type = sym->n_type & (N_TYPE | N_EXT);
-
- // Check that the symbols is a global and that it has a name.
- if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)
- || !sym->n_un.n_strx)
- continue;
-
- // Only search from the last '.' in the symbol.
- // but skip the leading '_' in all symbols first.
- symname = strbase + sym->n_un.n_strx + 1;
- dot = strrchr(symname, '.');
- if (!dot || strcmp(dot, kSuperClassSuffix))
- continue;
-
- // Got a candidate so hand it over for class processing.
- return_if(dot - symname >= (int) sizeof(classname),
- false, ("Symbol %s is too long\n", symname));
-
- bcopy(symname, classname, dot - symname);
- classname[dot - symname] = '\0';
- if (!recordClass(file, classname, sym))
- return false;
- }
-
- return_if(!file->fClassList, false, ("Internal error, "
- "getMetaClassGraph(%s) found no classes", file->fPath));
-
- DEBUG_LOG(("Found %d classes in %x for %s\n",
- DataGetLength(file->fClassList)/sizeof(void*),
- file->fClassList, file->fPath));
-
- return true;
-}
-
-static Boolean mergeOSObjectsForFile(const struct fileRecord *file)
-{
- int i, nmerged;
- Boolean foundDuplicates = false;
-
-DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl:
-
- if (!file->fClassList)
- return true;
-
- if (!sMergedFiles) {
- sMergedFiles = DataCreate(0);
- return_if(!sMergedFiles, false,
- ("Unable to allocate memory metaclass list\n", file->fPath));
- }
-
- // Check to see if we have already merged this file
- nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
- for (i = 0; i < nmerged; i++) {
- if (file == ((void **) DataGetPtr(sMergedFiles))[i])
- return true;
- }
-
- if (!sMergeMetaClasses) {
- sMergeMetaClasses = DataCreate(0);
- return_if(!sMergeMetaClasses, false,
- ("Unable to allocate memory metaclass list\n", file->fPath));
- }
- else { /* perform a duplicate check */
- int i, j, cnt1, cnt2;
- struct metaClassRecord **list1, **list2;
-
- list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
- cnt1 = DataGetLength(file->fClassList) / sizeof(*list1);
- list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
- cnt2 = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
-
- for (i = 0; i < cnt1; i++) {
- for (j = 0; j < cnt2; j++) {
- if (!strcmp(list1[i]->fClassName, list2[j]->fClassName)) {
- errprintf("duplicate class %s in %s & %s\n",
- list1[i]->fClassName,
- file->fPath, list2[j]->fFile->fPath);
- }
- }
- }
- }
- if (foundDuplicates)
- return false;
-
- return_if(!DataAppendBytes(sMergedFiles, &file, sizeof(file)), false,
- ("Unable to allocate memory to merge %s\n", file->fPath));
-
- return_if(!DataAppendData(sMergeMetaClasses, file->fClassList), false,
- ("Unable to allocate memory to merge %s\n", file->fPath));
-
- if (file == sKernelFile)
- sMergedKernel = true;
-
- return true;
-}
-
-// Returns a pointer to the base of the section offset by the sections
-// base address. The offset is so that we can add nlist::n_values directly
-// to this address and get a valid pointer in our memory.
-static unsigned char *
-getSectionForSymbol(const struct fileRecord *file, const struct nlist *symb,
- void ***endP)
-{
- const struct section *section;
- unsigned char sectind;
- unsigned char *base;
-
- sectind = symb->n_sect; // Default to symbols section
- if ((symb->n_type & N_TYPE) == N_ABS && file->fIsKernel) {
- // Absolute symbol so we have to iterate over our sections
- for (sectind = 1; sectind <= file->fNSects; sectind++) {
- unsigned long start, end;
-
- section = file->fSections[sectind - 1].fSection;
- start = section->addr;
- end = start + section->size;
- if (start <= symb->n_value && symb->n_value < end) {
- // Found the relevant section
- break;
- }
- }
- }
-
- // Is the vtable in a valid section?
- return_if(sectind == NO_SECT || sectind > file->fNSects,
- (unsigned char *) -1,
- ("%s isn't a valid kext, bad section reference\n", file->fPath));
-
- section = file->fSections[sectind - 1].fSection;
-
- // for when we start walking the vtable so compute offset's now.
- base = file->fMachO + section->offset;
- *endP = (void **) (base + section->size);
-
- return base - section->addr; // return with addr offset
-}
-
-static Boolean resolveKernelVTable(struct metaClassRecord *metaClass)
-{
- const struct fileRecord *file;
- struct patchRecord *patchedVTable;
- void **curEntry, **vtableEntries, **endSection;
- unsigned char *sectionBase;
- struct patchRecord *curPatch;
- int classSize;
-
- // Should never occur but it doesn't cost us anything to check.
- if (metaClass->fPatchedVTable)
- return true;
-
-DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl:
-
- // Do we have a valid vtable to patch?
- return_if(!metaClass->fVTableSym,
- false, ("Internal error - no class vtable symbol?\n"));
-
- file = metaClass->fFile;
-
- // If the metaClass we are being to ask is in the kernel then we
- // need to do a quick scan to grab the fPatchList in a reliable format
- // however we don't need to check the superclass in the kernel
- // as the kernel vtables are always correct wrt themselves.
- // Note this ends the superclass chain recursion.
- return_if(!file->fIsKernel,
- false, ("Internal error - resolveKernelVTable not kernel\n"));
-
- if (file->fNoKernelExecutable) {
- // Oh dear attempt to map the kernel's VM into my memory space
- return_if(file->fNoKernelExecutable, false,
- ("Internal error - fNoKernelExecutable not implemented yet\n"));
- }
-
- // We are going to need the base and the end
- sectionBase = getSectionForSymbol(file, metaClass->fVTableSym, &endSection);
- if (-1 == (long) sectionBase)
- return false;
-
- vtableEntries = (void **) (sectionBase + metaClass->fVTableSym->n_value);
- curEntry = vtableEntries + kVTablePreambleLen;
- for (classSize = 0; curEntry < endSection && *curEntry; classSize++)
- curEntry++;
-
- return_if(*curEntry, false, ("Bad kernel image, short section\n"));
-
- patchedVTable = (struct patchRecord *)
- malloc((classSize + 1) * sizeof(struct patchRecord));
- return_if(!patchedVTable, false, ("resolveKernelVTable - no memory\n"));
-
- // Copy the vtable of this class into the patch table
- curPatch = patchedVTable;
- curEntry = vtableEntries + kVTablePreambleLen;
- for (; *curEntry; curEntry++, curPatch++) {
- curPatch->fSymbol = (struct nlist *)
- findSymbolByAddress(file, *curEntry);
- curPatch->fType = kSymbolLocal;
- }
-
- // Tag the end of the patch vtable
- curPatch->fSymbol = NULL;
- metaClass->fPatchedVTable = patchedVTable;
-
- return true;
-}
-
-// reloc->fPatch must contain a valid pointer on entry
-static struct nlist *
-getNewSymbol(struct fileRecord *file,
- const struct relocRecord *reloc, const char *supername)
-{
- unsigned int size, i, namelen;
- struct nlist **sym;
- struct nlist *msym;
- const char *strbase;
- struct relocation_info *rinfo;
- long strx;
-
- if (!file->fNewSymbols) {
- file->fNewSymbols = DataCreate(0);
- return_if(!file->fNewSymbols, NULL,
- ("Unable to allocate new symbol table for %s\n", file->fPath));
- }
-
- // Make sure we have a string table as well for the new symbol
- if (!file->fNewStrings) {
- file->fNewStrings = DataCreate(0);
- return_if(!file->fNewStrings, NULL,
- ("Unable to allocate string table for %s\n", file->fPath));
- }
-
- rinfo = (struct relocation_info *) reloc->fRInfo;
- size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *);
- sym = (const struct nlist **) DataGetPtr(file->fNewSymbols);
- // remember that the n_strx for new symbols names is negated
- strbase = (const char *)
- DataGetPtr(file->fNewStrings) - file->fSymtab->strsize;
- for (i = 0; i < size; i++, sym++) {
- const char *symname = strbase - (*sym)->n_un.n_strx;
-
- if (!strcmp(symname, supername)) {
- rinfo->r_symbolnum = i + file->fSymtab->nsyms;
- file->fSymbolsDirty = true;
- return *sym;
- }
- }
-
- // Assert that this is a vaild symbol. I need this condition to be true
- // for the later code to make non-zero. So the first time through I'd
- // better make sure that it is 0.
- return_if(reloc->fSymbol->n_sect, NULL,
- ("Undefined symbol entry with non-zero section %s:%s\n",
- file->fPath, symbolname(file, reloc->fSymbol)));
-
- msym = (struct nlist *) malloc(sizeof(struct nlist));
- return_if(!msym,
- NULL, ("Unable to create symbol table entry for %s\n", file->fPath));
-
- // If we are here we didn't find the symbol so create a new one now
- if (!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym))) {
- free(msym);
- return_if(true,
- NULL, ("Unable to grow symbol table for %s\n", file->fPath));
- }
-
- namelen = strlen(supername) + 1;
- strx = DataGetLength(file->fNewStrings);
- if (!DataAppendBytes(file->fNewStrings, supername, namelen)) {
- free(msym);
- DataAddLength(file->fNewSymbols, -sizeof(struct nlist)); // Undo harm
- return_if(true, NULL,
- ("Unable to grow string table for %s\n", file->fPath));
- }
-
- // Offset the string index by the original string table size
- // and negate the address to indicate that this is a 'new' symbol
- msym->n_un.n_strx = -(strx + file->fSymtab->strsize);
- msym->n_type = (N_EXT | N_UNDF);
- msym->n_sect = NO_SECT;
- msym->n_desc = 0;
- msym->n_value = 0;
-
- // Mark the old symbol as being potentially deletable I can use the
- // n_sect field as the input symbol must be of type N_UNDF which means
- // that the n_sect field must be set to NO_SECT otherwise it is an
- // in valid input file.
- ((struct nlist *) reloc->fSymbol)->n_un.n_strx
- = -reloc->fSymbol->n_un.n_strx;
- ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
-
- rinfo->r_symbolnum = i + file->fSymtab->nsyms;
- file->fSymbolsDirty = true;
- return msym;
-}
-
-static struct nlist *
-fixOldSymbol(struct fileRecord *file,
- const struct relocRecord *reloc, const char *supername)
-{
- unsigned int namelen;
- struct nlist *sym = (struct nlist *) reloc->fSymbol;
- const char *oldname = symbolname(file, sym);
-
- // assert(sym->n_un.n_strx >= 0);
-
- namelen = strlen(supername);
- if (namelen < strlen(oldname)) {
- // Overwrite old string in string table
- strcpy((char *) oldname, supername);
- }
- else {
- long strx;
-
- // Make sure we have a string table as well for this symbol
- if (!file->fNewStrings) {
- file->fNewStrings = DataCreate(0);
- return_if(!file->fNewStrings, NULL,
- ("Unable to allocate string table for %s\n", file->fPath));
- }
-
- // Find the end of the fNewStrings data structure;
- strx = DataGetLength(file->fNewStrings);
- return_if(!DataAppendBytes(file->fNewStrings, supername, namelen + 1),
- NULL, ("Unable to grow string table for %s\n", file->fPath));
-
- // now add the current table size to the offset
- sym->n_un.n_strx = strx + file->fSymtab->strsize;
- }
-
- // Mark the symbol as having been processed by negating it.
- // Also note that we have dirtied the file and need to repair the
- // symbol table.
- sym->n_un.n_strx = -sym->n_un.n_strx;
- file->fSymbolsDirty = true;
- return sym;
-}
-
-static enum patchState
-symbolCompare(const struct fileRecord *file,
- const struct nlist *classsym,
- const char *supername)
-{
- const char *classname;
-
-
- // Check to see if the target function is locally defined
- // if it is then we can assume this is a local vtable override
- if ((classsym->n_type & N_TYPE) != N_UNDF)
- return kSymbolLocal;
-
- // Check to see if both symbols point to the same symbol name
- // if so then we are still identical.
- classname = symbolname(file, classsym);
- if (!strcmp(classname, supername))
- return kSymbolIdentical;
-
- // Right now we know that the target's vtable entry is different from the
- // superclass' vtable entry. This means that we will have to apply a
- // patch to the current entry, however before returning lets check to
- // see if we have a _RESERVEDnnn field 'cause we can use this as a
- // registration point that must align between vtables.
- if (!strncmp(supername, kReservedPrefix, sizeof(kReservedPrefix) - 1))
- return kSymbolMismatch;
-
- // OK, we have a superclass difference where the superclass doesn't
- // reference a pad function so assume that the superclass is correct.
- if (!strncmp(classname, kReservedPrefix, sizeof(kReservedPrefix) - 1))
- return kSymbolPadUpdate;
- else
- return kSymbolSuperUpdate;
-}
-
-static Boolean patchVTable(struct metaClassRecord *metaClass)
-{
- struct metaClassRecord *super = NULL;
- struct fileRecord *file;
- struct patchRecord *patchedVTable;
- struct relocRecord **curReloc, **vtableRelocs, **endSection;
- unsigned char *sectionBase;
- int classSize;
-
- // Should never occur but it doesn't cost us anything to check.
- if (metaClass->fPatchedVTable)
- return true;
-
- // Do we have a valid vtable to patch?
- return_if(!metaClass->fVTableSym,
- false, ("Internal error - no class vtable symbol?\n"));
-
- file = metaClass->fFile;
-
- // If the metaClass we are being to ask is in the kernel then we
- // need to do a quick scan to grab the fPatchList in a reliable format
- // however we don't need to check the superclass in the kernel
- // as the kernel vtables are always correct wrt themselves.
- // Note this ends the superclass chain recursion.
- return_if(file->fIsKernel,
- false, ("Internal error - patchVTable shouldn't used for kernel\n"));
-
- if (!metaClass->fSuperName)
- return false;
-
- // The class isn't in the kernel so make sure that the super class
- // is patched before patching ouselves.
- super = getClass(sMergeMetaClasses, metaClass->fSuperName);
- return_if(!super, false, ("Can't find superclass for %s : %s \n",
- metaClass->fClassName, metaClass->fSuperName));
-
- // Superclass recursion if necessary
- if (!super->fPatchedVTable) {
- Boolean res;
-
- if (super->fFile->fIsKernel)
- res = resolveKernelVTable(super);
- else
- res = patchVTable(super);
- if (!res)
- return false;
- }
-
-DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl:
-
- // We are going to need the base and the end
-
- sectionBase = getSectionForSymbol(file,
- metaClass->fVTableSym, (void ***) &endSection);
- if (-1 == (long) sectionBase)
- return false;
-
- vtableRelocs = (struct relocRecord **)
- (sectionBase + metaClass->fVTableSym->n_value);
- curReloc = vtableRelocs + kVTablePreambleLen;
- for (classSize = 0; curReloc < endSection && *curReloc; classSize++)
- curReloc++;
-
- return_if(*curReloc, false,
- ("%s isn't a valid kext, short section\n", file->fPath));
-
- patchedVTable = (struct patchRecord *)
- malloc((classSize + 1) * sizeof(struct patchRecord));
- return_if(!patchedVTable, false, ("patchedVTable - no memory\n"));
-
- do {
- struct patchRecord *curPatch;
- struct nlist *symbol;
-
- curPatch = patchedVTable;
- curReloc = vtableRelocs + kVTablePreambleLen;
-
- // Grab the super table patches if necessary
- // Can't be patching a kernel table as we don't walk super
- // class chains in the kernel symbol space.
- if (super && super->fPatchedVTable) {
- const struct patchRecord *spp;
-
- spp = super->fPatchedVTable;
-
- for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
- const char *supername =
- symbolname(super->fFile, spp->fSymbol);
-
- symbol = (struct nlist *) (*curReloc)->fSymbol;
-
- curPatch->fType = symbolCompare(file, symbol, supername);
- switch (curPatch->fType) {
- case kSymbolIdentical:
- case kSymbolLocal:
- break;
-
- case kSymbolSuperUpdate:
- symbol = getNewSymbol(file, (*curReloc), supername);
- break;
-
- case kSymbolPadUpdate:
- symbol = fixOldSymbol(file, (*curReloc), supername);
- break;
-
- case kSymbolMismatch:
- errprintf("%s is not compatible with its %s superclass, "
- "broken superclass?\n",
- metaClass->fClassName, super->fClassName);
- goto abortPatch;
-
- default:
- errprintf("Internal error - unknown patch type\n");
- goto abortPatch;
- }
- if (symbol) {
- curPatch->fSymbol = symbol;
- (*curReloc)->fSymbol = symbol;
- }
- else
- goto abortPatch;
- }
- }
-
- // Copy the remainder of this class' vtable into the patch table
- for (; *curReloc; curReloc++, curPatch++) {
- // Local reloc symbols
- curPatch->fType = kSymbolLocal;
- curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
- }
-
- // Tag the end of the patch vtable
- curPatch->fSymbol = NULL;
-
- metaClass->fPatchedVTable = patchedVTable;
- return true;
- } while(0);
-
-abortPatch:
- if (patchedVTable)
- free(patchedVTable);
-
- return false;
-}
-
-static Boolean growImage(struct fileRecord *file, vm_size_t delta)
-{
-#if !KERNEL
- file->fMachOSize += delta;
- return (file->fMachO + file->fMachOSize <= file->fPadEnd);
-#else /* KERNEL */
- vm_address_t startMachO, endMachO, endMap;
- vm_offset_t newMachO;
- vm_size_t newsize;
- unsigned long i, nsect, nclass = 0;
- struct metaClassRecord **classes = NULL;
- struct sectionRecord *section;
- kern_return_t ret;
-
- startMachO = (vm_address_t) file->fMachO;
- endMachO = startMachO + file->fMachOSize + delta;
- endMap = (vm_address_t) file->fMap + file->fMapSize;
-
- // Do we have room in the current mapped image
- if (endMachO < round_page(endMap)) {
- file->fMachOSize += delta;
- return true;
- }
-
- newsize = endMachO - startMachO;
- if (newsize < round_page(file->fMapSize)) {
- // We have room in the map if we shift the macho image within the
- // current map. We will have to patch up pointers into the object.
- newMachO = (vm_offset_t) file->fMap;
- bcopy((char *) startMachO, (char *) newMachO, file->fMachOSize);
- }
- else if (file->fIsKmem) {
- // kmem_alloced mapping so we can try a kmem_realloc
- ret = kmem_realloc(kernel_map,
- (vm_address_t) file->fMap,
- (vm_size_t) file->fMapSize,
- &newMachO,
- newsize);
- if (KERN_SUCCESS != ret)
- return false;
-
- // If the mapping didn't move then just return
- if ((vm_address_t) file->fMap == newMachO) {
- file->fMachOSize = file->fMapSize = newsize;
- return true;
- }
-
- // We have relocated the kmem image so we are going to have to
- // move all of the pointers into the image around.
- }
- else {
- // The image doesn't have room for us and I can't kmem_realloc
- // then I just have to bite the bullet and copy the object code
- // into a bigger memory segment
- ret = kmem_alloc(kernel_map, &newMachO, newsize);
-
- if (KERN_SUCCESS != ret)
- return false;
- bcopy((char *) startMachO, (void *) newMachO, file->fMachOSize);
- file->fIsKmem = true;
- }
-
-
- file->fMap = file->fMachO = (unsigned char *) newMachO;
- file->fMapSize = newsize;
- file->fMachOSize += delta; // Increment the image size
-
- // If we are here then we have shifted the object image in memory
- // I really should change all of my pointers into the image to machO offsets
- // but I have run out of time. So I'm going to very quickly go over the
- // cached data structures and add adjustments to the addresses that are
- // affected. I wonder how long it will take me to get them all.
- //
- // For every pointer into the MachO I need to add an adjustment satisfying
- // the following simultanous equations
- // addr_old = macho_old + fixed_offset
- // addr_new = macho_new + fixed_offset therefore:
- // addr_new = addr_old + (macho_new - macho_old)
-#define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) )
- delta = newMachO - startMachO;
-
- // Rebase the cached in object 'struct symtab_command' pointer
- REBASE(file->fSymtab, delta);
-
- // Rebase the cached in object 'struct nlist' pointer for all symbols
- REBASE(file->fSymbolBase, delta);
-
- // Rebase the cached in object 'struct nlist' pointer for local symbols
- REBASE(file->fLocalSyms, delta);
-
- // Rebase the cached in object 'char' pointer for the string table
- REBASE(file->fStringBase, delta);
-
- // Ok now we have to go over all of the relocs one last time
- // to clean up the pad updates which had their string index negated
- // to indicate that we have finished with them.
- section = file->fSections;
- for (i = 0, nsect = file->fNSects; i < nsect; i++, section++)
- REBASE(section->fSection, delta);
-
- // We only ever grow images that contain class lists so dont bother
- // the check if file->fClassList is non-zero 'cause it can't be
- // assert(file->fClassList);
- nclass = DataGetLength(file->fClassList)
- / sizeof(struct metaClassRecord *);
- classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
- for (i = 0; i < nclass; i++) {
- struct patchRecord *patch;
-
- for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) {
- vm_address_t symAddr = (vm_address_t) patch->fSymbol;
- if (symAddr >= startMachO && symAddr < endMachO)
- REBASE(patch->fSymbol, delta);
- }
- }
-
-
-#undef REBASE
-
- return true;
-
-#endif /* KERNEL */
-}
-
-static Boolean
-prepareFileForLink(struct fileRecord *file)
-{
- unsigned long i, last, numnewsyms, newsymsize, newstrsize;
- struct sectionRecord *section;
- struct nlist **symp, *sym;
-
- // If we didn't even do a pseudo 'relocate' and dirty the image
- // then we can just return now.
- if (!file->fImageDirty)
- return true;
-
-DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl:
-
- // We have to go over all of the relocs to repair the damage
- // that we have done to the image when we did our 'relocation'
- section = file->fSections;
- for (i = 0, last = file->fNSects; i < last; i++, section++) {
- unsigned char *sectionBase;
- struct relocRecord *rec;
- unsigned long j, nreloc;
-
- if (section->fRelocCache) {
- sectionBase = file->fMachO + section->fSection->offset;
- nreloc = section->fSection->nreloc;
- rec = (struct relocRecord *) DataGetPtr(section->fRelocCache);
-
- // We will need to repair the reloc list
- for (j = 0; j < nreloc; j++, rec++) {
- void **entry;
- struct nlist *sym;
-
- // Repair Damage to object image
- entry = (void **) (sectionBase + rec->fRInfo->r_address);
- *entry = rec->fValue;
-
- // Check if the symbol that this relocation entry points
- // to is marked as erasable
- sym = (struct nlist *) rec->fSymbol;
- if (sym && sym->n_type == (N_EXT | N_UNDF)
- && sym->n_sect == (unsigned char) -1) {
- // clear mark now
- sym->n_un.n_strx = -sym->n_un.n_strx;
- sym->n_sect = NO_SECT;
- }
- }
-
- // Clean up the fRelocCache we don't need it any more.
- DataRelease(section->fRelocCache);
- section->fRelocCache = 0;
- }
- }
- file->fImageDirty = false; // Image is clean
-
- // If we didn't dirty the symbol table then just return
- if (!file->fSymbolsDirty)
- return true;
-
- // calculate total file size increase and check against padding
- numnewsyms = (file->fNewSymbols)? DataGetLength(file->fNewSymbols) : 0;
- numnewsyms /= sizeof(struct nlist *);
- newsymsize = numnewsyms * sizeof(struct nlist);
- newstrsize = (file->fNewStrings)? DataGetLength(file->fNewStrings) : 0;
- newstrsize = (newstrsize + 3) & ~3; // Round to nearest word
-
- return_if(!growImage(file, newsymsize + newstrsize),
- false, ("Unable to patch the extension, no memory\n", file->fPath));
-
- // Push out the new symbol table if necessary
- if (numnewsyms) {
- caddr_t base;
-
- // Move the string table out of the way of the grown symbol table
- // Don't forget the '\0' from end of string table.
- base = (caddr_t) file->fStringBase;
- bcopy(base, base + newsymsize, file->fSymtab->strsize);
- file->fStringBase += newsymsize;
- file->fSymtab->stroff += newsymsize;
-
- // Now append the new symbols to the symbol table.
- base = (caddr_t) file->fSymbolBase
- + file->fSymtab->nsyms * sizeof(struct nlist);
- symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
- for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++)
- bcopy(*symp, base, sizeof(struct nlist));
- file->fSymtab->nsyms += numnewsyms;
-
- DataRelease(file->fNewSymbols);
- file->fNewSymbols = 0;
- }
-
- // Push out the new string table if necessary
- if (newstrsize) {
- caddr_t base = (caddr_t) file->fStringBase + file->fSymtab->strsize;
- unsigned long actuallen = DataGetLength(file->fNewStrings);
-
- // Set the last word in string table to zero before copying data
- *((unsigned long *) ((char *) base + newstrsize - 4)) = 0;
-
- // Now append the new strings to the end of the file
- bcopy((caddr_t) DataGetPtr(file->fNewStrings), base, actuallen);
-
- file->fSymtab->strsize += newstrsize;
-
- DataRelease(file->fNewStrings);
- file->fNewStrings = 0;
- }
-
- // Repair the symbol table string index values
- // I used negative strx's to indicate symbol has been processed
- sym = file->fSymbolBase;
- for (i = 0, last = file->fSymtab->nsyms; i < last; i++, sym++) {
- if (sym->n_un.n_strx < 0) {
- if ( sym->n_type != (N_EXT | N_UNDF)
- || (unsigned char) -1 != sym->n_sect)
- sym->n_un.n_strx = -sym->n_un.n_strx;
- else {
- // This symbol isn't being used by any vtable's reloc so
- // convert it into an N_ABS style of symbol, remove the
- // external bit and null out the symbol name.
- bzero(sym, sizeof(*sym));
- sym->n_type = N_ABS; /* type flag, see below */
- }
- }
- }
- file->fSymbolsDirty = false;
-
- return true;
-}
-
-Boolean
-#if KERNEL
-kld_file_map(const char *pathName,
- unsigned char *map,
- size_t mapSize,
- Boolean isKmem)
-#else
-kld_file_map(const char *pathName)
-#endif /* KERNEL */
-{
- struct fileRecord file, *fp = 0;
-
- // Already done no need to repeat
- fp = getFile(pathName);
- if (fp)
- return true;
-
- bzero(&file, sizeof(file));
- file.fPath = pathName;
-
-#if KERNEL
- file.fMap = map;
- file.fMapSize = mapSize;
- file.fIsKmem = isKmem;
-#else
- if (!mapObjectFile(&file))
- return false;
-#endif /* KERNEL */
-
- do {
- const struct machOMapping {
- struct mach_header h;
- struct load_command c[1];
- } *machO;
- const struct load_command *cmd;
- const struct nlist *sym;
- unsigned int i, firstlocal, nsyms;
- unsigned long strsize;
- const char *strbase;
- Boolean foundOSObject;
-
- if (!findBestArch(&file))
- break;
-
- machO = (const struct machOMapping *) file.fMachO;
- if (file.fMachOSize < machO->h.sizeofcmds)
- break;
-
- // If the file type is MH_EXECUTE then this must be a kernel
- // as all Kernel extensions must be of type MH_OBJECT
- for (i = 0, cmd = &machO->c[0]; i < machO->h.ncmds; i++) {
- if (cmd->cmd == LC_SEGMENT) {
- return_if(!parseSegments(&file, (struct segment_command *) cmd),
- false, ("%s isn't a valid mach-o, bad segment\n",
- file.fPath));
- }
- else if (cmd->cmd == LC_SYMTAB)
- file.fSymtab = (struct symtab_command *) cmd;
-
- cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
- }
- break_if(!file.fSymtab,
- ("%s isn't a valid mach-o, no symbols\n", file.fPath));
-
- // we found a link edit segment so recompute the bases
- if (file.fSymbolBase) {
- struct segment_command *link =
- (struct segment_command *) file.fSymbolBase;
-
- file.fSymbolBase = (struct nlist *)
- (link->vmaddr + (file.fSymtab->symoff - link->fileoff));
- file.fStringBase = (char *)
- (link->vmaddr + (file.fSymtab->stroff - link->fileoff));
- break_if( ( (caddr_t) file.fStringBase + file.fSymtab->strsize
- > (caddr_t) link->vmaddr + link->vmsize ),
- ("%s isn't a valid mach-o le, bad symbols\n", file.fPath));
- }
- else {
- file.fSymbolBase = (struct nlist *)
- (file.fMachO + file.fSymtab->symoff);
- file.fStringBase = (char *)
- (file.fMachO + file.fSymtab->stroff);
- break_if( ( file.fSymtab->stroff + file.fSymtab->strsize
- > file.fMachOSize ),
- ("%s isn't a valid mach-o, bad symbols\n", file.fPath));
- }
-
- // If this file the kernel and do we have an executable image
- file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
- file.fNoKernelExecutable = (vm_page_size == file.fSymtab->symoff)
- && (file.fSections[0].fSection->size == 0);
-
- // Search for the first non-stab symbol in table
- strsize = file.fSymtab->strsize;
- strbase = file.fStringBase;
- sym = file.fSymbolBase;
- firstlocal = 0;
- foundOSObject = false;
- for (i = 0, nsyms = file.fSymtab->nsyms; i < nsyms; i++, sym++) {
- if ((unsigned long) sym->n_un.n_strx > strsize)
- break;
-
- // Find the first exported symbol
- if ( !file.fLocalSyms && (sym->n_type & N_EXT) ) {
- file.fLocalSyms = sym;
- firstlocal = i;
- }
-
- // Find the a OSObject based subclass by searching for symbols
- // that have a suffix of '.superClass'
- if (!foundOSObject
- && ((sym->n_type & (N_TYPE | N_EXT)) == (N_SECT | N_EXT)
- || (sym->n_type & (N_TYPE | N_EXT)) == (N_ABS | N_EXT))
- && sym->n_un.n_strx) {
- const char *dot;
-
- // Only search from the last '.' in the symbol.
- // but skip the leading '_' in all symbols first.
- dot = strrchr(strbase + sym->n_un.n_strx + 1, '.');
- if (dot && !strcmp(dot, kSuperClassSuffix))
- foundOSObject = true;
- }
-
- // Find the last local symbol
- if ( !file.fNLocal && sym->n_type == (N_EXT | N_UNDF) )
- file.fNLocal = i - firstlocal;
-
- }
- break_if(i < nsyms,
- ("%s isn't a valid mach-o, bad symbol strings\n", file.fPath));
-
- break_if(!file.fLocalSyms, ("%s has no symbols?\n", file.fPath));
-
- // If we don't have any undefined symbols then all symbols
- // must be local so just compute it now if necessary.
- if ( !file.fNLocal )
- file.fNLocal = i - firstlocal;
-
- fp = addFile(&file);
- if (!fp)
- break;
-
- if (foundOSObject && !getMetaClassGraph(fp))
- break;
-
- if (file.fIsKernel)
- sKernelFile = fp;
-#if KERNEL
- if (!sKernelFile) {
- extern struct mach_header _mh_execute_header;
- extern struct segment_command *getsegbyname(char *seg_name);
-
- struct segment_command *sg;
- size_t kernelSize;
- Boolean ret;
-
- sg = (struct segment_command *) getsegbyname(kLinkEditSegName);
- break_if(!sg, ("Can't find kernel link edit segment\n"));
-
- kernelSize = sg->vmaddr + sg->vmsize - (size_t) &_mh_execute_header;
- ret = kld_file_map(kld_basefile_name,
- (unsigned char *) &_mh_execute_header, kernelSize,
- /* isKmem */ false);
- break_if(!ret, ("kld can't map kernel file"));
- }
-#endif /* KERNEL */
-
- return true;
- } while(0);
-
- removeFile(&file);
-
- return false;
-}
-
-void *kld_file_getaddr(const char *pathName, long *size)
-{
- struct fileRecord *file = getFile(pathName);
-
- if (!file)
- return 0;
-
- if (size)
- *size = file->fMachOSize;
-
- return file->fMachO;
-}
-
-void *kld_file_lookupsymbol(const char *pathName, const char *symname)
-{
- struct fileRecord *file = getFile(pathName);
- const struct nlist *sym;
- const struct section *section;
- unsigned char *sectionBase;
- unsigned char sectind;
-
- return_if(!file,
- NULL, ("Unknown file %s\n", pathName));
-
- sym = findSymbolByName(file, symname);
-
- // May be a non-extern symbol so look for it there
- if (!sym) {
- const char *strbase;
- unsigned int i, nsyms;
-
- sym = file->fSymbolBase;
- strbase = file->fStringBase;
- for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
- if ( (sym->n_type & N_EXT) ) {
- sym = 0;
- break; // Terminate search when we hit an extern
- }
- if ( (sym->n_type & N_STAB) )
- continue;
- if ( !strcmp(symname, strbase + sym->n_un.n_strx) )
- break;
- }
- }
-
- return_if(!sym,
- NULL, ("Unknown symbol %s in %s\n", symname, pathName));
-
- // Is the vtable in a valid section?
- sectind = sym->n_sect;
- return_if(sectind == NO_SECT || sectind > file->fNSects, NULL,
- ("Malformed object file, invalid section reference for %s in %s\n",
- symname, pathName));
-
- section = file->fSections[sectind - 1].fSection;
- sectionBase = file->fMachO + section->offset - section->addr;
-
- return (void *) (sectionBase + sym->n_value);
-}
-
-Boolean kld_file_merge_OSObjects(const char *pathName)
-{
- struct fileRecord *file = getFile(pathName);
-
- return_if(!file,
- false, ("Internal error - unable to find file %s\n", pathName));
-
- return mergeOSObjectsForFile(file);
-}
-
-Boolean kld_file_patch_OSObjects(const char *pathName)
-{
- struct fileRecord *file = getFile(pathName);
- struct metaClassRecord **classes;
- unsigned long i, last;
-
- return_if(!file,
- false, ("Internal error - unable to find file %s\n", pathName));
-
-DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl:
-
- // If we don't have any classes we can return now.
- if (!file->fClassList)
- return true;
-
- // If we haven't alread merged the kernel then do it now
- if (!sMergedKernel && sKernelFile)
- mergeOSObjectsForFile(sKernelFile);
- return_if(!sMergedKernel, false, ("Internal error no kernel?\n"));
-
- if (!mergeOSObjectsForFile(file))
- return false;
-
- // Patch all of the classes in this executable
- last = DataGetLength(file->fClassList) / sizeof(void *);
- classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
- for (i = 0; i < last; i++) {
- if (!patchVTable(classes[i]))
- return false;
- }
-
- return true;
-}
-
-Boolean kld_file_prepare_for_link()
-{
- if (sMergedFiles) {
- unsigned long i, nmerged = 0;
- struct fileRecord **files;
-
- // Check to see if we have already merged this file
- nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
- files = (struct fileRecord **) DataGetPtr(sMergedFiles);
- for (i = 0; i < nmerged; i++) {
- if (!prepareFileForLink(files[i]))
- return false;
- }
- }
-
- // Clear down the meta class table and merged file lists
- DataRelease(sMergeMetaClasses);
- DataRelease(sMergedFiles);
- sMergedFiles = sMergeMetaClasses = NULL;
- sMergedKernel = false;
-
- return true;
-}
-
-void kld_file_cleanup_all_resources()
-{
- unsigned long i, nfiles;
-
-#if KERNEL // @@@ gvdl:
- // Debugger("kld_file_cleanup_all_resources");
-#endif
-
- if (!sFilesTable || !(nfiles = DataGetLength(sFilesTable)))
- return; // Nothing to do just return now
-
- nfiles /= sizeof(struct fileRecord *);
- for (i = 0; i < nfiles; i++)
- removeFile(((void **) DataGetPtr(sFilesTable))[i]);
-
- // Don't really have to clean up anything more as the whole
- // malloc engine is going to be released and I couldn't be bothered.
-}
-
-#if !KERNEL
-Boolean kld_file_debug_dump(const char *pathName, const char *outName)
-{
- const struct fileRecord *file = getFile(pathName);
- int fd;
- Boolean ret = false;
-
- return_if(!file, false, ("Unknown file %s for dumping\n", pathName));
-
- fd = open(outName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
- return_if(-1 == fd, false, ("Can't create output file %s - %s(%d)\n",
- outName, strerror(errno), errno));
-
- do {
- break_if(-1 == write(fd, file->fMachO, file->fMachOSize),
- ("Can't dump output file %s - %s(%d)\n",
- outName, strerror(errno), errno));
- ret = true;
- } while(0);
-
- close(fd);
-
- return ret;
-}
-#endif /* !KERNEL */
-
+++ /dev/null
-/*
- * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * History:
- * 2001-05-30 gvdl Initial implementation of the vtable patcher.
- */
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-#if KERNEL
-extern Boolean kld_file_map(const char *pathName,
- unsigned char *map, size_t mapSize,
- Boolean isKmem);
-#else
-extern Boolean kld_file_map(const char *pathName);
-
-extern void *
- kld_file_lookupsymbol(const char *pathName, const char *symbolname);
-
-Boolean kld_file_debug_dump(const char *pathName, const char *outName);
-#endif /* KERNEL */
-
-extern void *kld_file_getaddr(const char *pathName, long *size);
-
-extern Boolean kld_file_merge_OSObjects(const char *pathName);
-
-extern Boolean kld_file_patch_OSObjects(const char *pathName);
-
-extern Boolean kld_file_prepare_for_link();
-
-extern void kld_file_cleanup_all_resources();
-
-__END_DECLS
+++ /dev/null
-.\"
-.\" Copyright (c) 1997 Doug Rabson
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (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: kmodload.8,v 1.3 2000/12/15 05:33:01 lindak Exp $
-.\"
-.Dd April 8, 1999
-.Dt KMODLOAD 8
-.Os FreeBSD
-.Sh NAME
-.Nm kmodload
-.Nd loads and starts a kernel module
-.Sh SYNOPSIS
-.Nm kmodload
-.Op Fl v
-.Op Fl k Ar kernelfile
-.Op Fl d Ar dependencyfile
-.Op Fl o Ar symbolfile
-.Ar modulefile
-.Sh DESCRIPTION
-The
-.Nm
-loads the file
-.Ar modulefile
-into the kernel and starts its execution.
-.Pp
-The following options are available:
-.Bl -tag -width indent
-.It Fl v
-Be more verbose.
-.It Fl k Ar kernelfile
-Use alternate file
-.Ar kernelfile
-instead of default file /mach for linking
-.Ar modulefile .
-.It Fl d Ar dependencyfile
-Add symbols from
-.Ar dependencyfile
-to kernel symbols prior to linking of
-.Ar modulefile .
-The file
-.Ar dependencyfile
-must already be loaded.
-.It Fl o Ar symbolfile
-Creates file named
-.Ar symbolfile
-that contains statically linked output suitable to use with
-.Xr gdb 1
-for remote debugging.
-.El
-.Sh FILES
-.Bl -tag -width /modules -compact
-.It Pa /System/Library/Extensions
-directory containing loadable kernel modules.
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success.
-A status of 1 indicates a usage error.
-A status of 2 indicates a indicates a permissions error.
-A status of 3 indicates a problem with linking the module.
-A status of 4 indicates a internal or system error.
-A status of 5 indicates the module has already been loaded.
-.Sh SEE ALSO
-.Xr kmodstat 8 ,
-.Xr kmodsyms 8 ,
-.Xr kmodunload 8
-.Sh HISTORY
-The
-.Nm
-command is based on the command kldload written by
-.An Doug Rabson Aq dfr@FreeBSD.org
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*-
- * Copyright (c) 1997 Doug Rabson
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Original code from:
- * "kldload.c,v 1.5 1998/07/06 06:58:32 charnier Exp"
- */
-#ifndef lint
-static const char rcsid[] =
- "$Id: kmodload.c,v 1.10 2001/08/02 20:57:01 lindak Exp $";
-#endif /* not lint */
-
-#include <stdlib.h>
-#include <err.h>
-#include <sys/file.h>
-#include <nlist.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include <paths.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-#include <mach/mach_host.h>
-#include <mach-o/kld.h>
-#include <mach-o/fat.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "kld_patch.h"
-
-#define KMOD_ERROR_USAGE 1
-#define KMOD_ERROR_PERMS 2
-#define KMOD_ERROR_LOADING 3
-#define KMOD_ERROR_INTERNAL 4
-#define KMOD_ERROR_ALREADY 5
-
-#define kKMOD_INFO_SYMBOLNAME "_kmod_info"
-#define kKmodsymsName "kmodsyms"
-
-static mach_port_t kernel_port;
-static mach_port_t kernel_priv_port;
-
-static kmod_info_t *module_dependencies = 0;
-static vm_address_t kernel_alloc_address = 0;
-static unsigned long kernel_alloc_size = 0;
-static vm_address_t kernel_load_address = 0;
-static unsigned long kernel_load_size = 0;
-static unsigned long kernel_hdr_size = 0;
-static unsigned long kernel_hdr_pad = 0;
-static unsigned long faked_kernel_load_address = 0;
-
-static kmod_info_t *loaded_modules = 0;
-static int loaded_count = 0;
-
-static char *progname = "program name?";
-static int kmodsyms = 0;
-static int link_addrs_set = 0;
-static int verbose = 0;
-
-static char *debugdumpfile = NULL;
-
-// must not be static; kld library calls
-extern void kld_error_vprintf(const char *format, va_list ap);
-static void e_printf(const char *fmt, ...);
-static void v_printf(const char *fmt, ...);
-
-static void machwarn(int error, const char *message);
-static void macherr(int error, const char *message);
-
-static unsigned long linkedit_address(unsigned long size,
- unsigned long headers_size);
-static void abort_load(int exitcode, const char *fmt, ...);
-static void map_and_patch(const char *base,
- const char **library_paths,
- const char *module);
-static void link_base(const char *base,
- const char **dependency_paths,
- const vm_address_t *dependency_addrs);
-static void clear_globals(void);
-static kmod_info_t *map_module(const char *filename);
-static struct mach_header *link_module(const char *filename,
- const char *output);
-static vm_address_t update_kmod_info(struct mach_header *mach_header);
-static kmod_t load_module(struct mach_header *mach_header,
- vm_address_t info);
-static void set_module_dependencies(kmod_t id);
-static void start_module(kmod_t id);
-
-static void
-usage(void)
-{
- if (kmodsyms) {
- fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n", progname);
- fprintf(stderr, " %s [-v] -k kernelfile [-d dependencyfile@address] -o symbolfile modulefile@address\n",
- progname);
- } else {
- fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n", progname);
- }
- fflush(stderr);
- exit(KMOD_ERROR_USAGE);
-}
-
-int
-main(int argc, char** argv)
-{
- int c, r, i;
- char * kernel = _PATH_UNIX;
- int kernel_set = 0;
- char * gdbfile = 0;
-#define MAX_DEPENDANCIES 128
- char * dependencies[MAX_DEPENDANCIES];
- vm_address_t loaded_addresses[MAX_DEPENDANCIES];
- int dependency_count = 0;
- struct mach_header *rld_header;
-
- char * module_path = "";
- vm_address_t module_info = 0;
- vm_address_t module_faked_address = 0;
- kmod_t module_id = 0;
- kmod_info_t *file_kinfo;
-
- if ((progname = strrchr(argv[0], '/')) == NULL)
- progname = argv[0];
- else
- ++progname;
-
- kmodsyms = !strcmp(progname, kKmodsymsName);
-
- // XXX things to add:
- // -p data string to send as outofband data on start
- // -P data file to send as outofband data on start
-
- while ((c = getopt(argc, argv, "D:d:o:k:v")) != -1)
- switch (c) {
- case 'd':
- dependencies[dependency_count] = optarg;
- if (kmodsyms) {
- char *address;
- if ((address = strrchr(optarg, '@'))) {
- *address++ = 0;
- loaded_addresses[dependency_count] = strtoul(address, NULL, 0);
- link_addrs_set++;
- } else {
- loaded_addresses[dependency_count] = 0;
- }
- }
- if (++dependency_count == MAX_DEPENDANCIES) {
- abort_load(KMOD_ERROR_INTERNAL,
- "internal error, dependency count overflow.");
- }
- break;
- case 'o':
- gdbfile = optarg;
- break;
- case 'k':
- kernel_set++;
- kernel = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'D':
- debugdumpfile = optarg;
- break;
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- dependencies[dependency_count] = 0;
- loaded_addresses[dependency_count] = 0;
-
- if (argc != 1) usage();
-
- module_path = argv[0];
-
- if (kmodsyms) {
- char *address;
-
- if (!gdbfile) usage();
-
- // check for @address
- if ((address = strrchr(module_path, '@'))) {
- *address++ = 0;
- module_faked_address = strtoul(address, NULL, 0);
- link_addrs_set++;
- } else {
- module_faked_address = 0;
- }
-
- // if any arg uses @address then they all must be and the kernel must be set
- if (link_addrs_set) {
- if (!kernel_set) usage();
- if (!module_faked_address) usage();
- for (i=0; i < dependency_count; i++) {
- if (!loaded_addresses[i]) usage();
- }
- }
- }
-
- // map the module if possible, map_module will fail if there is a problem
- file_kinfo = map_module(module_path);
-
- if (!link_addrs_set) {
- kmod_info_t *k;
-
- // we only need the kernel port if we need to lookup loaded kmods
- r = task_for_pid(mach_task_self(), 0, &kernel_port);
- machwarn(r, "unable to get kernel task port");
- if (KERN_SUCCESS != r) {
- abort_load(KMOD_ERROR_PERMS,
- "You must be running as root to load modules in the kernel.");
- }
-
- //get loaded modules
- r = kmod_get_info(kernel_port, (void *)&loaded_modules, &loaded_count); // never freed
- macherr(r, "kmod_get_info() failed");
-
- // check to see if the module has been loaded
- k = loaded_modules;
- while (k) {
- if (!strcmp(k->name, file_kinfo->name)) {
- if (!kmodsyms) {
- abort_load(KMOD_ERROR_ALREADY,
- "the module named '%s' is already loaded.", k->name);
- } else {
- module_faked_address = k->address;
- }
- break;
- }
- k = (k->next) ? (k + 1) : 0;
- }
-
- if (kmodsyms && !module_faked_address) {
- abort_load(KMOD_ERROR_USAGE,
- "the module named '%s' has not been loaded.", file_kinfo->name);
- }
-
- //XXX it would be nice to be able to verify this is the correct kernel
- //XXX by comparing the kernel version strings (once we have them)
- }
-
- map_and_patch(kernel, dependencies, module_path);
- if (debugdumpfile) kld_file_debug_dump(module_path, debugdumpfile);
-
- // Tell the kld linker where to get its load address from
- kld_address_func(linkedit_address);
-
- // link the kernel along with any dependencies
- link_base(kernel, dependencies, loaded_addresses);
-
- if (kmodsyms) {
- faked_kernel_load_address = module_faked_address;
-
- if (!faked_kernel_load_address) {
- abort_load(KMOD_ERROR_INTERNAL,
- "internal error, fell thru without setting module load address.");
- }
- }
-
- rld_header = link_module(module_path, gdbfile);
- module_info = update_kmod_info(rld_header);
-
- if (kmodsyms) return 0;
-
- // we need the priv port to load modules into the kernel
- kernel_priv_port = mach_host_self(); /* if we are privileged */
-
- module_id = load_module(rld_header, module_info);
- set_module_dependencies(module_id);
- start_module(module_id);
-
- return 0;
-}
-
-static void
-machwarn(int error, const char *message)
-{
- if (KERN_SUCCESS != error)
- e_printf("%s: %s", message, mach_error_string(error));
-}
-
-static void
-macherr(int error, const char *message)
-{
- if (KERN_SUCCESS != error)
- abort_load(KMOD_ERROR_INTERNAL,
- "%s: %s", message, mach_error_string(error));
-}
-
-static kmod_info_t *map_module(const char *filename)
-{
- kmod_info_t *file_kinfo;
-
- if (!kld_file_map(filename))
- exit(KMOD_ERROR_LOADING);
-
- file_kinfo = kld_file_lookupsymbol(filename, kKMOD_INFO_SYMBOLNAME);
- if (!file_kinfo) {
- abort_load(KMOD_ERROR_USAGE,
- "%s is not a valid kernel module.", filename);
- }
-
- return file_kinfo;
-}
-
-static void
-map_and_patch(const char *base, const char **library_paths, const char *module)
-{
- if (!kld_file_map(base))
- exit(KMOD_ERROR_INTERNAL);
- if (!kld_file_merge_OSObjects(base))
- abort_load(KMOD_ERROR_LOADING, NULL);
-
- if (*library_paths) {
- char **library;
- for (library = library_paths; *library; library++) {
- map_module(*library);
- if (!kld_file_patch_OSObjects(*library))
- abort_load(KMOD_ERROR_LOADING, NULL);
- }
- }
-
- // Patch the vtables of the object module we are about to load
- // The module has already been mapped in the main() routine as part
- // of validation
- if (!kld_file_patch_OSObjects(module))
- abort_load(KMOD_ERROR_LOADING, NULL);
-
- // During the patch up process the mapped images were modified
- // to avoid having to allocate more data than necessary.
- // Now we have to give the patcher a chance to clean up after itself.
- if (!kld_file_prepare_for_link())
- abort_load(KMOD_ERROR_LOADING, NULL);
-}
-
-static void
-link_base(const char *base,
- const char **dependency_paths,
- const vm_address_t *dependency_addrs)
-{
- struct mach_header *rld_header;
- char *base_addr;
- long base_size;
- int ok;
-
- // Get the address and size of the base, usually the kernel
- base_addr = kld_file_getaddr(base, &base_size);
- if (!base_addr)
- exit(KMOD_ERROR_INTERNAL); // Error reported by kld library.
-
- ok = kld_load_basefile_from_memory(base, base_addr, base_size);
- fflush(stdout);
- if (!ok)
- abort_load(KMOD_ERROR_LOADING, "kld_load_basefile(%s) failed.", base);
-
- if (*dependency_paths) {
- char **dependency = dependency_paths;
- const vm_address_t *load_addr = dependency_addrs;
-
- while (*dependency) {
- kmod_info_t *file_kinfo;
-
- // Find the kmod_info structure in the image.
- file_kinfo =
- kld_file_lookupsymbol(*dependency, kKMOD_INFO_SYMBOLNAME);
- if (!file_kinfo) {
- abort_load(KMOD_ERROR_USAGE,
- "%s is not a valid kernel module.", *dependency);
- }
-
- // find the address that this dependency is loaded at
- if (kmodsyms && *load_addr) {
- faked_kernel_load_address = *load_addr;
- } else {
- kmod_info_t *k;
- kmod_info_t *tmp;
- int found_it = 0;
-
- // match up file version of kmod_info with kernel version
- k = loaded_modules;
- while (k) {
- if (!strcmp(k->name, file_kinfo->name)) {
- if (strcmp(k->version, file_kinfo->version)) {
- e_printf("loaded kernel module '%s' version differs.", *dependency);
- abort_load(KMOD_ERROR_LOADING,
- "loaded version '%s', file version '%s'.",
- k->version, file_kinfo->version);
- }
- found_it++;
- break;
- }
- k = (k->next) ? (k + 1) : 0;
- }
- if (!found_it) {
- abort_load(KMOD_ERROR_USAGE,
- "kernel module '%s' is not loaded.", *dependency);
- }
-
- tmp = malloc(sizeof(kmod_info_t));
- if (!tmp)
- abort_load(KMOD_ERROR_LOADING, "no memory.");
-
- *tmp = *k;
- tmp->next = module_dependencies;
- module_dependencies = tmp;
-
- faked_kernel_load_address = k->address;
- }
-
- rld_header = link_module(*dependency, 0);
-
- (void) update_kmod_info(rld_header);
-
- dependency++; load_addr++;
- }
- /* make sure we clear these so clean up does the right thing. */
- clear_globals();
- }
-}
-
-#if !defined(page_round)
-#define page_trunc(p) ((int)(p)&~(vm_page_size-1))
-#define page_round(p) page_trunc((int)(p)+vm_page_size-1)
-#endif
-
-static unsigned long
-linkedit_address(unsigned long size, unsigned long headers_size)
-{
- int r;
- unsigned long round_segments_size;
- unsigned long round_headers_size;
- unsigned long round_size;
-
- kernel_load_size = size; // The actual size allocated by kld_load...
-
- round_headers_size = page_round(headers_size);
- round_segments_size = page_round(size - headers_size);
- round_size = round_headers_size + round_segments_size;
-
- kernel_alloc_size = round_size;
- kernel_hdr_size = headers_size; // will need to be rounded to page *after* link.
- kernel_hdr_pad = round_headers_size - headers_size;
-
- if (faked_kernel_load_address) {
- kernel_load_address = faked_kernel_load_address + kernel_hdr_pad;
- v_printf("Returning fake load address of 0x%8x", kernel_load_address);
- return kernel_load_address;
- }
- if (kmodsyms) {
- abort_load(KMOD_ERROR_INTERNAL,
- "internal error, almost tried to alloc kernel memory.");
- }
-
- r = vm_allocate(kernel_port, &kernel_alloc_address,
- kernel_alloc_size, TRUE);
- macherr(r, "unable to allocate kernel memory");
-
- v_printf("allocated %ld bytes in kernel space at 0x%8x",
- kernel_alloc_size, kernel_alloc_address);
-
- kernel_load_address = kernel_alloc_address + kernel_hdr_pad;
-
- v_printf("Returning load address of 0x%x", kernel_load_address);
-
- return kernel_load_address;
-}
-
-static void
-clear_globals(void)
-{
- faked_kernel_load_address = 0;
- kernel_alloc_address = 0;
- kernel_alloc_size = 0;
- kernel_load_address = 0;
- kernel_load_size = 0;
- kernel_hdr_size = 0;
- kernel_hdr_pad = 0;
- return;
-}
-
-static struct mach_header *
-link_module(const char *filename, const char *output)
-{
- struct mach_header *rld_header;
- char *object_addr;
- long object_size;
- int ok;
-
- // Get the address of the thined MachO image.
- object_addr = kld_file_getaddr(filename, &object_size);
- if (!object_addr)
- abort_load(KMOD_ERROR_LOADING, NULL);
-
- ok = kld_load_from_memory(&rld_header, filename,
- object_addr, object_size, output);
- fflush(stdout);
- if (!ok)
- abort_load(KMOD_ERROR_LOADING, "kld_load() failed.");
-
- return rld_header;
-}
-
-// Update the kmod_info_t structure in the image to be laoded
-// Side effect of removing the kKMOD_INFO_SYMBOLNAME from the
-// loaded symbol name space, otherwise we would have a duplicate
-// defined symbol failure
-vm_address_t
-update_kmod_info(struct mach_header *mach_header)
-{
- char * symbol = kKMOD_INFO_SYMBOLNAME;
- kmod_info_t *info;
- unsigned long value;
- int ok;
-
- ok = kld_lookup(symbol, &value); fflush(stdout);
- if (!ok)
- abort_load(KMOD_ERROR_LOADING, "kld_lookup(%s) failed.", symbol);
-
- ok = kld_forget_symbol(symbol); fflush(stdout);
- if (!ok)
- abort_load(KMOD_ERROR_LOADING, "kld_forget_symbol(%s) failed.", symbol);
-
- /* Get the kmod info by translating from the kernel address at value.
- */
- info = (kmod_info_t *)(value - (unsigned long)kernel_load_address + (unsigned long)mach_header);
- v_printf("kmod name: %s", info->name);
- v_printf("kmod start @ 0x%x", (vm_address_t)info->start);
- v_printf("kmod stop @ 0x%x", (vm_address_t)info->stop);
-
- /* Record link info in kmod info struct, rounding the hdr_size to fit
- * the adjustment that was made.
- */
- info->address = kernel_alloc_address;
- info->size = kernel_alloc_size;
- info->hdr_size = page_round(kernel_hdr_size);
-
- if (!info->start)
- abort_load(KMOD_ERROR_LOADING, "invalid start address?");
- else if (!info->stop)
- abort_load(KMOD_ERROR_LOADING, "invalid stop address?");
-
- return (vm_address_t)value;
-}
-
-static kmod_t
-load_module(struct mach_header *mach_header, vm_address_t info)
-{
- int r;
- kmod_t id;
- vm_address_t vm_buffer = 0;
-
- r = vm_allocate(mach_task_self(), &vm_buffer,
- kernel_alloc_size, TRUE);
- macherr(r, "unable to vm_allocate() copy buffer");
-
- /* Copy the linked segment data into the page-aligned buffer.
- * Do not round the header size here.
- */
- bzero((void *)vm_buffer, kernel_alloc_size);
- memcpy((void *)vm_buffer, mach_header, kernel_hdr_size);
- memcpy((void *)vm_buffer + page_round(kernel_hdr_size),
- (void *)((unsigned long)mach_header + kernel_hdr_size),
- kernel_load_size - kernel_hdr_size);
-
- // copy linked header into kernel address space
- r = vm_write(kernel_port, kernel_alloc_address,
- vm_buffer, kernel_alloc_size);
- macherr(r, "unable to write module into kernel memory");
-
- // let the kernel know about it
- r = kmod_create(kernel_priv_port, info, &id);
- macherr(r, "unable to register module with kernel");
-
- v_printf("kmod id %d successfully created at 0x%x size %ld.\n",
- id, kernel_alloc_address, kernel_alloc_size);
-
- // FIXME: make sure this happens even on failure
-
- vm_deallocate(mach_task_self(), vm_buffer, kernel_alloc_size);
- return id;
-}
-
-static void
-set_module_dependencies(kmod_t id)
-{
- int r;
- void * args = 0;
- int argsCount= 0;
- kmod_info_t *module = module_dependencies;
-
- while (module) {
-
- r = kmod_control(kernel_priv_port, KMOD_PACK_IDS(id, module->id), KMOD_CNTL_RETAIN, &args, &argsCount);
- machwarn(r, "kmod_control(retain) failed");
- if (r) {
- clear_globals();
- r = kmod_destroy(kernel_priv_port, id);
- macherr(r, "kmod_destroy failed");
- }
-
- v_printf("kmod id %d reference count was sucessfully incremented.", module->id);
-
- module = module->next;
- }
-}
-
-static void
-start_module(kmod_t id)
-{
- int r;
- void * args = 0;
- int argsCount= 0;
-
- r = kmod_control(kernel_priv_port, id, KMOD_CNTL_START, &args, &argsCount);
- machwarn(r, "kmod_control(start) failed");
- if (r) {
- clear_globals();
- kmod_destroy(kernel_priv_port, id);
- macherr(r, "kmod_destroy failed");
- }
-
- v_printf("kmod id %d successfully started.", id);
-}
-
-static void e_printf(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- kld_error_vprintf(fmt, ap);
- va_end(ap);
-}
-
-static void v_printf(const char *fmt, ...)
-{
- va_list ap;
- char msg[1024];
-
- if (!verbose) return;
-
- va_start(ap, fmt);
- vsnprintf(msg, sizeof(msg), fmt, ap);
- va_end(ap);
-
- printf("%s: %s\n", progname, msg);
-}
-
-static void abort_load(int exitcode, const char *fmt, ...)
-{
- if (fmt) {
- va_list ap;
-
- va_start(ap, fmt);
- kld_error_vprintf(fmt, ap);
- va_end(ap);
- }
-
- if (!faked_kernel_load_address
- && (kernel_alloc_address || kernel_alloc_size)) {
- int r;
-
- v_printf("freeing %ld bytes in kernel space at 0x%x",
- kernel_alloc_size, kernel_alloc_address);
- r = vm_deallocate(kernel_port, kernel_alloc_address, kernel_alloc_size);
- machwarn(r, "unable to cleanup kernel memory");
- }
-
- exit(exitcode);
-}
-
-__private_extern__ void
-kld_error_vprintf(const char *fmt, va_list ap)
-{
- char msg[1024];
-
- vsnprintf(msg, sizeof(msg), fmt, ap);
- fprintf(stderr, "%s: %s", progname, msg);
-
- fflush(stderr);
-}
+++ /dev/null
-.\"
-.\" Copyright (c) 1997 Doug Rabson
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (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: kmodsyms.8,v 1.2 2000/02/24 22:31:35 lindak Exp $
-.\"
-.Dd April 8, 1999
-.Dt KMODSYMS 8
-.Os FreeBSD
-.Sh NAME
-.Nm kmodsyms
-.Nd creates a statically linked symbol file for remote debugging
-.Sh SYNOPSIS
-.Nm kmodsyms
-.Op Fl v
-.Op Fl k Ar kernelfile
-.Op Fl d Ar dependencyfile
-.Fl o Ar symbolfile
-.Ar modulefile
-.Nm kmodsyms
-.Op Fl v
-.Fl k Ar kernelfile
-.Op Fl d Ar dependencyfile@address
-.Fl o Ar symbolfile
-.Ar modulefile@address
-.Sh DESCRIPTION
-The
-.Nm
-creates a statically linked symbol file for remote debugging using
-.Ar modulefile[@address] .
-If an address is specified for either the
-.Ar modulefile
-or
-.Ar dependacyfile
-they both must have the address tag. If addresses are specified it assumed that the command is being run on a different machine with a potentially different kernel, thus the
-.Ar kernelfile
-argument is also required.
-If addresses are not specified they taken from the currently running host machine.
-.Pp
-The following options are available:
-.Bl -tag -width indent
-.It Fl v
-Be more verbose.
-.It Fl k Ar kernelfile
-Use alternate file
-.Ar kernelfile
-instead of default file /mach for linking
-.Ar modulefile .
-.It Fl d Ar dependacyfile[@address]
-Add symbols from
-.Ar dependacyfile
-to kernel symbols prior to linking of
-.Ar modulefile .
-The file
-.Ar dependacyfile
-must already be loaded.
-.It Fl o Ar symbolfile
-Creates file named
-.Ar symbolfile
-that contains statically linked output suitable to use with
-.Xr gdb 1
-for remote debugging.
-.El
-.Sh FILES
-.Bl -tag -width /modules -compact
-.It Pa /System/Library/Extensions
-directory containing loadable kernel modules.
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success.
-A status of 1 indicates a usage error.
-A status of 2 indicates a indicates a permissions error.
-A status of 3 indicates a problem with linking the module.
-A status of 4 indicates a internal or system error.
-.Sh SEE ALSO
-.Xr kmodload 8 ,
-.Xr kmodstat 8 ,
-.Xr kmodunload 8
-.Sh HISTORY
-The
-.Nm
-command is based on the command kldload written by
-.An Doug Rabson Aq dfr@FreeBSD.org
+++ /dev/null
-#
-# Generated by the NeXT Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kmodstat
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-CFILES = kmodstat.c
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kmodstat.8
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /usr/sbin
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-###############################################################################
-# Makefile.postamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile, which is imported after all other makefiles, to
-# override attributes for a project's Makefile environment. This allows you
-# to take advantage of the environment set up by the other Makefiles.
-# You can also define custom rules at the end of this file.
-#
-###############################################################################
-#
-# These variables are exported by the standard makefiles and can be
-# used in any customizations you make. They are *outputs* of
-# the Makefiles and should be used, not set.
-#
-# PRODUCTS: products to install. All of these products will be placed in
-# the directory $(DSTROOT)$(INSTALLDIR)
-# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
-# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
-# OFILE_DIR: Directory into which .o object files are generated.
-# DERIVED_SRC_DIR: Directory used for all other derived files
-#
-# ALL_CFLAGS: flags to pass when compiling .c files
-# ALL_MFLAGS: flags to pass when compiling .m files
-# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
-# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
-# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
-# ALL_LDFLAGS: flags to pass when linking object files
-# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
-# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
-# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
-# ALL_YFLAGS: flags to pass when processing .y (yacc) files
-# ALL_LFLAGS: flags to pass when processing .l (lex) files
-#
-# NAME: name of application, bundle, subproject, palette, etc.
-# LANGUAGES: langages in which the project is written (default "English")
-# English_RESOURCES: localized resources (e.g. nib's, images) of project
-# GLOBAL_RESOURCES: non-localized resources of project
-#
-# SRCROOT: base directory in which to place the new source files
-# SRCPATH: relative path from SRCROOT to present subdirectory
-#
-# INSTALLDIR: Directory the product will be installed into by 'install' target
-# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-#
-# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
-#
-###############################################################################
-
-# Some compiler flags can be overridden here for certain build situations.
-#
-# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
-# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
-# to -g)
-# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
-# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
-# to -O)
-# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
-# to -pg -DPROFILE)
-# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
-# the include path (defaults to -I.)
-# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
-# passed to ld/libtool (defaults to nothing)
-
-
-# Library and Framework projects only:
-# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
-# against the framework will run against the correct version even if
-# the current version of the framework changes. You may override this
-# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
-# development cycle, but be sure to restore it before installing.
-
-
-# Ownership and permissions of files installed by 'install' target
-
-#INSTALL_AS_USER = root
- # User/group ownership
-#INSTALL_AS_GROUP = wheel
- # (probably want to set both of these)
-#INSTALL_PERMISSIONS =
- # If set, 'install' chmod's executable to this
-
-
-# Options to strip. Note: -S strips debugging symbols (executables can be stripped
-# down further with -x or, if they load no bundles, with no options at all).
-
-#STRIPFLAGS = -S
-
-
-#########################################################################
-# Put rules to extend the behavior of the standard Makefiles here. Include them in
-# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
-#
-# You should avoid redefining things like "install" or "app", as they are
-# owned by the top-level Makefile API and no context has been set up for where
-# derived files should go.
-#
-
-after_install::
- -mkdir -p ${DSTROOT}/usr/share/man/man8
- -rm -f ${DSTROOT}/usr/share/man/man8/kmodstat.8
- cp kmodstat.8 ${DSTROOT}/usr/share/man/man8/kmodstat.8
- chmod og-w ${DSTROOT}/usr/share/man/man8/kmodstat.8
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = ();
- OTHER_LINKED = (kmodstat.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kmodstat.8);
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_INSTALLDIR = /usr/sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kmodstat;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-.\"
-.\" Copyright (c) 1997 Doug Rabson
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (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: kmodstat.8,v 1.1.1.1 2000/01/11 02:10:18 wsanchez Exp $
-.\"
-.Dd April 8, 1999
-.Dt KMODSTAT 8
-.Os FreeBSD
-.Sh NAME
-.Nm kmodstat
-.Nd display status of dynamically loaded kernel modules
-.Sh SYNOPSIS
-.Nm kmodstat
-.Op Fl i Ar id
-.Op Fl n Ar name
-.Sh DESCRIPTION
-The
-.Nm
-utility displays the status of any kernel modules dynamically
-linked into the kernel.
-.Pp
-The following options are available:
-.Bl -tag -width indentXX
-.It Fl i Ar id
-Display the status of only the kernel module with this ID.
-.It Fl n Ar name
-Display the status of only the kernel module with this name.
-.El
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success
-and with a nonzero status if an error occurs.
-.Sh SEE ALSO
-.Xr kmodload 8 ,
-.Xr kmodsyms 8 ,
-.Xr kmodunload 8
-.Sh HISTORY
-The
-.Nm
-command is based on the command kldstat written by
-.An Doug Rabson Aq dfr@FreeBSD.org
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*-
- * Copyright (c) 1997 Doug Rabson
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Original code from:
- * "kldstat.c,v 1.5 1998/11/07 00:29:09 des Exp";
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$Id: kmodstat.c,v 1.3 2000/04/26 21:27:57 lindak Exp $";
-#endif /* not lint */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/param.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-#include <mach/mach_host.h>
-
-static void
-machwarn(int error, const char *message)
-{
- if (error == KERN_SUCCESS) return;
- fprintf(stderr, "kmodstat: %s: %s\n", message, mach_error_string(error));
-}
-
-static void
-macherr(int error, const char *message)
-{
- if (error == KERN_SUCCESS) return;
- fprintf(stderr, "kmodstat: %s: %s\n", message, mach_error_string(error));
- exit(1);
-}
-
-static int
-kmod_compare(const void *a, const void *b)
-{
- return (((kmod_info_t *)a)->id - ((kmod_info_t *)b)->id);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: kmodstat [-i id] [-n name]\n");
- exit(1);
-}
-
-int
-main(int argc, char** argv)
-{
- int c, idset = 0, id = 0;
- char* name = 0;
- kmod_info_t *info, *k;
- kmod_reference_t *r;
- int i, j, rc, foundit, count, rcount;
- mach_port_t kernel_port;
-
- while ((c = getopt(argc, argv, "i:n:")) != -1)
- switch (c) {
- case 'i':
- idset++;
- id = atoi(optarg);
- break;
- case 'n':
- name = optarg;
- break;
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (!idset && !name && (argc == 1)) {
- name = *argv;
- argc--;
- }
-
- if (argc != 0) usage();
-
- rc = task_for_pid(mach_task_self(), 0, &kernel_port);
- machwarn(rc, "unable to get kernel task port");
- if (rc) {
- fprintf(stderr, "kmodstat: Are you running as root?\n");
- exit(1);
- }
-
- rc= kmod_get_info(kernel_port, (void *)&info, &count);
- macherr(rc, "kmod_get_info() failed");
-
- k = info; count = 0;
- while (k) {
- count++;
- k = (k->next) ? (k + 1) : 0;
- }
-
- k = info; r = (kmod_reference_t *)(info + count);
- while (k) {
- if ((rcount = (int)k->reference_list)) {
- k->reference_list = r;
- for (i=0; i < rcount; i++) {
- foundit = 0;
- for (j=0; j < count; j++) {
- if (r->info == info[j].next) {
- r->info = (kmod_info_t *)info[j].id;
- foundit++;
- break;
- }
- }
- // force the id in here, the sorting below messes up the pointers
- if (!foundit) r->info = (kmod_info_t *)info[count - 1].id;
- r->next = r + 1;
- r++;
- }
- k->reference_list[rcount - 1].next = 0;
- }
- k = (k->next) ? (k + 1) : 0;
- }
-
- printf("Id Refs Address Size Wired Name (Version) <Linked Against>\n");
-
- if (!count) return 0;
-
- qsort(info, count, sizeof(kmod_info_t), kmod_compare);
-
- if (idset || name) {
- kmod_info_t *k = info;
- int match_count = 0;
- for (i=0; i < count; i++, k++) {
- if ((idset && id == k->id) || (name && !strcmp(k->name, name))) {
- info[match_count++] = *k;
- }
- }
- count = match_count;
- }
- for (i=0; i < count; i++, info++) {
- printf("%2d %4d %-10p %-10p %-10p %s (%s)",
- info->id, info->reference_count, (void *)info->address,
- (void *)info->size, (void *)(info->size - info->hdr_size),
- info->name, info->version);
-
- if ((r = info->reference_list)) {
- printf(" <%d", (int)r->info);
- r = r->next;
- while (r) {
- printf(" %d", (int)r->info);
- r = r->next;
- }
- printf(">");
- }
- printf("\n");
- }
-
- return 0;
-}
+++ /dev/null
-#
-# Generated by the NeXT Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = kmodunload
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-CFILES = kmodunload.c
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble kmodunload.8
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /sbin
-WINDOWS_INSTALLDIR = /Library/Executables
-PDO_UNIX_INSTALLDIR = /bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-###############################################################################
-# Makefile.postamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile, which is imported after all other makefiles, to
-# override attributes for a project's Makefile environment. This allows you
-# to take advantage of the environment set up by the other Makefiles.
-# You can also define custom rules at the end of this file.
-#
-###############################################################################
-#
-# These variables are exported by the standard makefiles and can be
-# used in any customizations you make. They are *outputs* of
-# the Makefiles and should be used, not set.
-#
-# PRODUCTS: products to install. All of these products will be placed in
-# the directory $(DSTROOT)$(INSTALLDIR)
-# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
-# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
-# OFILE_DIR: Directory into which .o object files are generated.
-# DERIVED_SRC_DIR: Directory used for all other derived files
-#
-# ALL_CFLAGS: flags to pass when compiling .c files
-# ALL_MFLAGS: flags to pass when compiling .m files
-# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
-# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
-# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
-# ALL_LDFLAGS: flags to pass when linking object files
-# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
-# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
-# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
-# ALL_YFLAGS: flags to pass when processing .y (yacc) files
-# ALL_LFLAGS: flags to pass when processing .l (lex) files
-#
-# NAME: name of application, bundle, subproject, palette, etc.
-# LANGUAGES: langages in which the project is written (default "English")
-# English_RESOURCES: localized resources (e.g. nib's, images) of project
-# GLOBAL_RESOURCES: non-localized resources of project
-#
-# SRCROOT: base directory in which to place the new source files
-# SRCPATH: relative path from SRCROOT to present subdirectory
-#
-# INSTALLDIR: Directory the product will be installed into by 'install' target
-# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
-# to prefix this with DSTROOT when you use it.
-#
-# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
-#
-###############################################################################
-
-# Some compiler flags can be overridden here for certain build situations.
-#
-# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
-# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
-# to -g)
-# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
-# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
-# to -O)
-# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
-# to -pg -DPROFILE)
-# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
-# the include path (defaults to -I.)
-# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
-# passed to ld/libtool (defaults to nothing)
-
-
-# Library and Framework projects only:
-# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
-# against the framework will run against the correct version even if
-# the current version of the framework changes. You may override this
-# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
-# development cycle, but be sure to restore it before installing.
-
-
-# Ownership and permissions of files installed by 'install' target
-
-#INSTALL_AS_USER = root
- # User/group ownership
-#INSTALL_AS_GROUP = wheel
- # (probably want to set both of these)
-#INSTALL_PERMISSIONS =
- # If set, 'install' chmod's executable to this
-
-
-# Options to strip. Note: -S strips debugging symbols (executables can be stripped
-# down further with -x or, if they load no bundles, with no options at all).
-
-#STRIPFLAGS = -S
-
-
-#########################################################################
-# Put rules to extend the behavior of the standard Makefiles here. Include them in
-# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
-#
-# You should avoid redefining things like "install" or "app", as they are
-# owned by the top-level Makefile API and no context has been set up for where
-# derived files should go.
-#
-
-after_install::
- -mkdir -p ${DSTROOT}/usr/share/man/man8
- -rm -f ${DSTROOT}/usr/share/man/man8/kmodunload.8
- cp kmodunload.8 ${DSTROOT}/usr/share/man/man8/kmodunload.8
- chmod og-w ${DSTROOT}/usr/share/man/man8/kmodunload.8
+++ /dev/null
-###############################################################################
-# Makefile.preamble
-# Copyright 1997, Apple Computer, Inc.
-#
-# Use this makefile for configuring the standard application makefiles
-# associated with ProjectBuilder. It is included before the main makefile.
-# In Makefile.preamble you set attributes for a project, so they are available
-# to the project's makefiles. In contrast, you typically write additional rules or
-# override built-in behavior in the Makefile.postamble.
-#
-# Each directory in a project tree (main project plus subprojects) should
-# have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults: The OTHER_* variables will be
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible. To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
-# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-# .cc, .cxx, .C, and .M files. There is no need to respecify the
-# flags in OTHER_MFLAGS, etc.
-# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
-# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
-# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
-# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
-# precompiling header files
-# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
-# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
-# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
-# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
-# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every
-# stage of the make:
-#
-# BEFORE_PREBUILD: targets to build before installing headers for a subproject
-# AFTER_PREBUILD: targets to build after installing headers for a subproject
-# BEFORE_BUILD_RECURSION: targets to make before building subprojects
-# BEFORE_BUILD: targets to make before a build, but after subprojects
-# AFTER_BUILD: targets to make after a build
-#
-# BEFORE_INSTALL: targets to build before installing the product
-# AFTER_INSTALL: targets to build after installing the product
-# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-# BEFORE_INSTALLHDRS: targets to build before installing headers for a
-# subproject
-# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-# AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-# BEFORE_DEPEND: targets to build before building dependencies for a
-# subproject
-# AFTER_DEPEND: targets to build after building dependencies for a
-# subproject
-#
-# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-# updated every time the project is built. If NO, the dependency
-# file is only built when the depend target is invoked.
-
-# Framework-related variables:
-# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the framework's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-# PUBLIC_HEADER_DIR: Determines where public exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically. For library projects you should
-# set this to something like /Developer/Headers/$(NAME). Do not set
-# this variable for framework projects unless you do not want the
-# header files included in the framework.
-# PRIVATE_HEADER_DIR: Determines where private exported header files
-# should be installed. Do not include $(DSTROOT) in this value --
-# it is prefixed automatically.
-# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
-# whether the libraries produced are statically linked when they
-# are used or if they are dynamically loadable. This defaults to
-# DYNAMIC.
-# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
-# where to put the library's DLL. This variable defaults to
-# $(INSTALLDIR)/../Executables
-#
-# INSTALL_AS_USER: owner of the intalled products (default root)
-# INSTALL_AS_GROUP: group of the installed products (default wheel)
-# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
-#
-# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-# passed on the command line to recursive invocations of make. Note that
-# the values in OTHER_*FLAGS are inherited by subprojects automatically --
-# you do not have to (and shouldn't) add OTHER_*FLAGS to
-# OTHER_RECURSIVE_VARIABLES.
-
-# Additional headers to export beyond those in the PB.project:
-# OTHER_PUBLIC_HEADERS
-# OTHER_PROJECT_HEADERS
-# OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-# OTHER_RESOURCES: (non-localized) resources for this project
-# OTHER_OFILES: relocatables to be linked into this project
-# OTHER_LIBS: more libraries to link against
-# OTHER_PRODUCT_DEPENDS: other dependencies of this project
-# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-# OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-# BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed. By default it is YES.
-# STRIP_ON_INSTALL = NO
-
-# Uncomment to suppress generation of a KeyValueCoding index when installing
-# frameworks (This index is used by WOB and IB to determine keys available
-# for an object). Set to YES by default.
-# PREINDEX_FRAMEWORK = NO
-
-# Change this definition to install projects somewhere other than the
-# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
-# and "" on other systems.
-DSTROOT = $(HOME)
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = ();
- OTHER_LINKED = (kmodunload.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, kmodunload.8);
- };
- LANGUAGE = English;
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_INSTALLDIR = /sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
- PDO_UNIX_INSTALLDIR = /bin;
- PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = kmodunload;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_INSTALLDIR = /Library/Executables;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-.\"
-.\" Copyright (c) 1997 Doug Rabson
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (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: kmodunload.8,v 1.1.1.1 2000/01/11 02:10:18 wsanchez Exp $
-.\"
-.Dd April 8, 1999
-.Dt KMODUNLOAD 8
-.Os FreeBSD
-.Sh NAME
-.Nm kmodunload
-.Nd stops and unloads a kernel module
-.Sh SYNOPSIS
-.Nm kmodunload
-.Op Fl v
-.Fl i Ar id
-.Nm kmodunload
-.Op Fl v
-.Fl n Ar name
-.Sh DESCRIPTION
-The
-.Nm
-utility stops and unloads a kernel module which was previously loaded with
-.Xr kmodload 8 .
-.Pp
-The following options are available:
-.Bl -tag -width indentXX
-.It Fl v
-Be more verbose.
-.It Fl i Ar id
-Unload the kernel module with this ID.
-.It Fl n Ar name
-Unload the kernel module with this name.
-.El
-.Sh DIAGNOSTICS
-The
-.Nm
-utility exits with a status of 0 on success
-and with a nonzero status if an error occurs.
-.Sh SEE ALSO
-.Xr kmodload 8 ,
-.Xr kmodstat 8 ,
-.Xr kmodsyms 8
-.Sh HISTORY
-The
-.Nm
-command is based on the command kldunload written by
-.An Doug Rabson Aq dfr@FreeBSD.org
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*-
- * Copyright (c) 1997 Doug Rabson
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Original code from:
- * "kldunload.c,v 1.7 1998/11/07 00:42:52 des Exp"
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$Id: kmodunload.c,v 1.3 2001/02/05 19:53:16 lindak Exp $";
-#endif /* not lint */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-#include <mach/mach_host.h>
-
-static int verbose = 0;
-#define v_printf if (verbose) printf
-
-static void
-machwarn(int error, const char *message)
-{
- if (error == KERN_SUCCESS) return;
- fprintf(stderr, "kmodunload: %s: %s\n", message, mach_error_string(error));
-}
-
-static void
-macherr(int error, const char *message)
-{
- if (error == KERN_SUCCESS) return;
- fprintf(stderr, "kmodunload: %s: %s\n", message, mach_error_string(error));
- exit(1);
-}
-
-static mach_port_t kernel_priv_port;
-
-static void
-stop_module(kmod_t id)
-{
- int r;
- void * args = 0;
- int argsCount= 0;
-
- r = kmod_control(kernel_priv_port, id, KMOD_CNTL_STOP, &args, &argsCount);
- macherr(r, "kmod_control(stop) failed");
-
- v_printf("kmodunload: kmod id %d successfully stopped.\n", id);
-}
-
-static void
-unload_module(kmod_t id)
-{
- int r;
-
- r = kmod_destroy(kernel_priv_port, id);
- macherr(r, "kmod_destroy() failed");
-
- v_printf("kmodunload: kmod id %d successfully unloaded.\n", id);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: kmodunload [-v] -i id\n");
- fprintf(stderr, " kmodunload [-v] -n name\n");
- exit(1);
-}
-
-int
-main(int argc, char** argv)
-{
- int c;
- int id = 0;
- char* name = 0;
- kmod_info_t *info;
- int r;
- int count;
- mach_port_t kernel_port;
-
- while ((c = getopt(argc, argv, "i:n:v")) != -1)
- switch (c) {
- case 'i':
- id = atoi(optarg);
- break;
- case 'n':
- name = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (!id && !name && (argc == 1)) {
- name = *argv;
- argc--;
- }
-
- if ((argc != 0) || (id && name))
- usage();
-
- if ((id == 0) && (name == 0))
- usage();
-
- r = task_for_pid(mach_task_self(), 0, &kernel_port);
- machwarn(r, "unable to get kernel task port");
- if (r) {
- fprintf(stderr, "kmodunload: Are you running as root?\n");
- exit(1);
- }
-
- r = kmod_get_info(kernel_port, (void *)&info, &count);
- macherr(r, "kmod_get_info() failed");
-
- if (count < 1) {
- fprintf(stderr, "kmodunload: there is nothing to unload?\n");
- exit(1);
- }
-
- if (name) {
- kmod_info_t *k = info;
- while (k) {
- if (!strcmp(k->name, name)) {
- id = k->id;
- break;
- }
- k = (k->next) ? (k + 1) : 0;
- }
- if (!k) {
- fprintf(stderr, "kmodunload: can't kmod named: %s.\n", name);
- exit(1);
- }
- } else {
- kmod_info_t *k = info;
- while (k) {
- if (id == k->id) {
- name = k->name;
- break;
- }
- k = (k->next) ? (k + 1) : 0;
- }
- if (!name) {
- fprintf(stderr, "kmodunload: can't find kmod id %d.\n", id);
- exit(1);
- }
- }
-
- v_printf("kmodunload: found kmod %s, id %d.\n", name, id);
- kernel_priv_port = mach_host_self(); /* if we are privileged */
-
- stop_module(id);
- unload_module(id);
-
- return 0;
-}
-
CFILES = ktrace.c subr.c
-OTHERSRCS = Makefile.preamble Makefile ktrace.1
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble ktrace.1
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
--- /dev/null
+install-man-page:
+ install -d $(DSTROOT)/usr/share/man/man1
+ install -c -m 444 ktrace.1 $(DSTROOT)/usr/share/man/man1/ktrace.1
+
OTHER_GENERATED_OFILES = $(VERS_OFILE)
+AFTER_INSTALL += install-man-page
M_FILES = ();
OTHER_LIBS = ();
OTHER_LINKED = (ktrace.c, subr.c);
- OTHER_SOURCES = (Makefile.preamble, Makefile, ktrace.1);
+ OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, ktrace.1);
SUBPROJECTS = ();
};
LANGUAGE = English;
.\" SUCH DAMAGE.
.\"
.\" @(#)ktrace.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/ktrace/ktrace.1,v 1.8.2.5 2001/08/16 13:16:53 ru Exp $
.\"
.Dd June 6, 1993
.Dt KTRACE 1
-.Os BSD 4.4
+.Os
.Sh NAME
.Nm ktrace
.Nd enable kernel process tracing
.Sh SYNOPSIS
-.Nm ktrace
+.Nm
.Op Fl aCcdi
.Op Fl f Ar trfile
-.Op Fl g Ar pgrp
-.Op Fl p Ar pid
+.Op Fl g Ar pgrp | Fl p Ar pid
.Op Fl t Ar trstr
-.Nm ktrace
+.Nm
.Op Fl adi
.Op Fl f Ar trfile
.Op Fl t Ar trstr
-command
+.Ar command
.Sh DESCRIPTION
-.Nm Ktrace
-enables kernel trace logging for the specified processes.
+The
+.Nm
+command enables kernel trace logging for the specified processes.
Kernel trace data is logged to the file
.Pa ktrace.out .
The kernel operations that are traced include system calls, namei
The following command is sufficient to disable tracing on all user owned
processes, and, if executed by root, all processes:
.Pp
-.Dl \&$ trace -C
+.Dl \&$ ktrace -C
.Pp
The trace file is not human readable; use
.Xr kdump 1
The options are as follows:
.Bl -tag -width indent
.It Fl a
-Append to the trace file instead of truncating it.
+Append to the trace file instead of recreating it.
.It Fl C
Disable tracing on all user owned processes, and, if executed by root, all
processes in the system.
.It Fl d
Descendants; perform the operation for all current children of the
designated processes.
-.It Fl f Ar file
+.It Fl f Ar file
Log trace records to
.Ar file
instead of
.Pa ktrace.out .
-.It Fl g Ar pgid
+.It Fl g Ar pgid
Enable (disable) tracing on all processes in the process group (only one
.Fl g
flag is permitted).
.It Fl i
Inherit; pass the trace flags to all future children of the designated
processes.
-.It Fl p Ar pid
+.It Fl p Ar pid
Enable (disable) tracing on the indicated process id (only one
.Fl p
flag is permitted).
-.It Fl t Ar trstr
+.It Fl t Ar trstr
The string argument represents the kernel trace points, one per letter.
The following table equates the letters with the tracepoints:
.Pp
.Tn I/O
.It Cm s
trace signal processing
+.It Cm u
+userland traces
+.It Cm w
+context switches
.El
.It Ar command
Execute
.Dl $ ktrace -C
.Sh SEE ALSO
.Xr kdump 1
+.Sh BUGS
+Only works if
+.Ar file
+is a regular file.
.Sh HISTORY
The
-.Nm ktrace
-command appears in
+.Nm
+command appeared in
.Bx 4.4 .
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
/*-
* Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* SUCH DAMAGE.
*/
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/ktrace/ktrace.c,v 1.12.2.3 2001/07/11 00:29:27 mikeh Exp $";
+#endif /* not lint */
+
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <err.h>
#include <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
#include "ktrace.h"
enum { NOTSET, CLEAR, CLEARALL } clear;
int append, ch, fd, inherit, ops, pid, pidset, trpoints;
char *tracefile;
+ mode_t omask;
+ struct stat sb;
clear = NOTSET;
append = ops = pidset = inherit = 0;
trpoints = DEF_POINTS;
tracefile = DEF_TRACEFILE;
- while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != EOF)
+ while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != -1)
switch((char)ch) {
case 'a':
append = 1;
trpoints = ALL_POINTS;
pid = 1;
} else
- ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
+ ops |= pidset ? KTROP_CLEAR : KTROP_CLEARFILE;
if (ktrace(tracefile, ops, trpoints, pid) < 0)
- err(1, tracefile);
+ err(1, "%s", tracefile);
exit(0);
}
- if ((fd = open(tracefile, O_CREAT | O_WRONLY | (append ? 0 : O_TRUNC),
- DEFFILEMODE)) < 0)
- err(1, tracefile);
+ omask = umask(S_IRWXG|S_IRWXO);
+ if (append) {
+ if ((fd = open(tracefile, O_CREAT | O_WRONLY, DEFFILEMODE)) < 0)
+ err(1, "%s", tracefile);
+ if (fstat(fd, &sb) != 0 || sb.st_uid != getuid())
+ errx(1, "Refuse to append to %s not owned by you.",
+ tracefile);
+ } else {
+ if (unlink(tracefile) == -1 && errno != ENOENT)
+ err(1, "unlink %s", tracefile);
+ if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY,
+ DEFFILEMODE)) < 0)
+ err(1, "%s", tracefile);
+ }
+ (void)umask(omask);
(void)close(fd);
if (*argv) {
if (ktrace(tracefile, ops, trpoints, getpid()) < 0)
- err(1, tracefile);
+ err(1, "%s", tracefile);
execvp(argv[0], &argv[0]);
err(1, "exec of '%s' failed", argv[0]);
}
else if (ktrace(tracefile, ops, trpoints, pid) < 0)
- err(1, tracefile);
+ err(1, "%s", tracefile);
exit(0);
}
void
usage()
{
- (void)fprintf(stderr,
-"usage:\tktrace [-aCcid] [-f trfile] [-g pgid] [-p pid] [-t [acgn]\n\tktrace [-aCcid] [-f trfile] [-t [acgn] command\n");
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: ktrace [-aCcdi] [-f trfile] [-g pgrp | -p pid] [-t cnisuw]",
+" ktrace [-adi] [-f trfile] [-t cnisuw] command");
exit(1);
}
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*/
#define DEF_POINTS (KTRFAC_SYSCALL | KTRFAC_SYSRET | KTRFAC_NAMEI | \
- KTRFAC_GENIO | KTRFAC_PSIG)
+ KTRFAC_GENIO | KTRFAC_PSIG | KTRFAC_USER)
#define ALL_POINTS (DEF_POINTS | KTRFAC_CSW)
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999, 2000-2001 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
/*-
* Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* SUCH DAMAGE.
*/
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/ktrace/subr.c,v 1.6 1999/08/28 01:02:34 peter Exp $";
+#endif /* not lint */
+
#include <sys/param.h>
#include <sys/file.h>
#include <sys/user.h>
case 's':
facs |= KTRFAC_PSIG;
break;
+ case 'u':
+ facs |= KTRFAC_USER;
+ break;
case 'w':
facs |= KTRFAC_CSW;
break;
NEXTSTEP_INSTALLDIR = /usr/bin
WINDOWS_INSTALLDIR = /Library/Executables
PDO_UNIX_INSTALLDIR = /bin
-LIBS =
+LIBS = -lcurses
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
/*
- cc -I. -DKERNEL_PRIVATE -O -o latency latency.c
+ cc -I. -DKERNEL_PRIVATE -O -o latency latency.c -lncurses
*/
#include <mach/mach.h>
#include <libc.h>
#include <termios.h>
-#include <bsd/curses.h>
+#include <curses.h>
#include <sys/ioctl.h>
#ifndef KERNEL_PRIVATE
double divisor;
int gotSIGWINCH = 0;
int trace_enabled = 0;
+struct host_basic_info hi;
+
#define SAMPLE_SIZE 300000
int decrementer_val = 0; /* Value used to reset decrementer */
int set_remove_flag = 1; /* By default, remove trace buffer */
+kd_buf **last_decrementer_kd; /* last DECR_TRAP per cpu */
+#define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
+
int
quit(s)
char *s;
exit(1);
}
-void sigquit()
+void leave() /* exit under normal conditions -- signal handler */
{
set_enable(0);
set_pidexclude(getpid(), 0);
exit(1);
}
-void sigterm()
-{
- set_enable(0);
- set_pidexclude(getpid(), 0);
- set_rtcdec(0);
- set_remove();
-
- exit(1);
-}
-
-
void
screen_update(FILE *fp)
{
double nanosecs_to_sleep;
int loop_cnt, sample_sc_now;
int decrementer_usec = 0;
+ kern_return_t ret;
+ int size;
+ int i, count;
+ host_name_port_t host;
void getdivisor();
void sample_sc();
void init_code_file();
getdivisor();
decrementer_val = decrementer_usec * divisor;
+ /* get the cpu count for the DECR_TRAP array */
+ host = mach_host_self();
+ size = sizeof(hi)/sizeof(int);
+ ret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &size);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((last_decrementer_kd = (kd_buf **)malloc(hi.avail_cpus * sizeof(kd_buf *))) == (kd_buf **)0)
+ quit("can't allocate memory for decrementer tracing info\n");
+
nanosecs_to_sleep = (double)(num_of_usecs_to_sleep * 1000);
fdelay = nanosecs_to_sleep * (divisor /1000);
adelay = (uint64_t)fdelay;
*/
set_rtcdec(decrementer_val);
- initscr();
+ if (initscr() == (WINDOW *) 0)
+ {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+
clear();
refresh();
signal(SIGWINCH, sigwinch);
signal(SIGINT, sigintr);
- signal(SIGQUIT, sigquit);
- signal(SIGTERM, sigterm);
+ signal(SIGQUIT, leave);
+ signal(SIGTERM, leave);
+ signal(SIGHUP, leave);
if ((my_buffer = malloc(SAMPLE_SIZE * sizeof(kd_buf))) == (char *)0)
}
}
if (gotSIGWINCH) {
- initscr();
+ /*
+ No need to check for initscr error return.
+ We won't get here if it fails on the first call.
+ */
+ endwin();
clear();
refresh();
void sample_sc(uint64_t start, uint64_t stop)
{
- kd_buf *kd, *last_mach_sched, *last_decrementer_kd, *start_kd, *end_of_sample;
+ kd_buf *kd, *last_mach_sched, *start_kd, *end_of_sample;
uint64_t now;
- int count;
+ int count, i;
int first_entry = 1;
char command[32];
double timestamp, last_timestamp, delta, start_bias;
count = needed;
if (bufinfo.flags & KDBG_WRAPPED) {
- int i;
-
for (i = 0; i < cur_max; i++) {
th_state[i].thread = 0;
th_state[i].type = -1;
}
}
end_of_sample = &((kd_buf *)my_buffer)[count];
- last_decrementer_kd = (kd_buf *)my_buffer;
+
+ /* Always reinitialize the DECR_TRAP array */
+ for (i=0; i < hi.avail_cpus; i++)
+ last_decrementer_kd[i] = (kd_buf *)my_buffer;
+
last_mach_sched = (kd_buf *)0;
for (kd = (kd_buf *)my_buffer; kd < end_of_sample; kd++) {
int len;
char *p;
long *sargptr;
+ kd_buf *cur_kd;
double i_latency;
struct th_info *ti;
char command1[32];
else if (debugid & DBG_FUNC_END)
exit_syscall(log_fp, kd, thread, type, command, timestamp, delta, start_bias, 0);
else if (type == DECR_TRAP) {
+ cur_kd = kd;
if (log_fp && i_thresh_hold && (int)i_latency > i_thresh_hold) {
- start_kd = last_decrementer_kd;
+ start_kd = last_decrementer_kd[cpunum];
kd = log_decrementer(start_kd, kd, end_of_sample, i_latency);
-
if (kd >= end_of_sample)
break;
}
- last_decrementer_kd = kd;
+ if ((kd->debugid & DBG_FUNC_MASK) == DECR_TRAP)
+ {
+ cpunum = (kd->arg5 & KDBG_CPU_MASK) ? 1: 0;
+ last_decrementer_kd[cpunum] = kd;
+ }
+ else
+ last_decrementer_kd[cpunum] = cur_kd;
}
continue;
}
if (first_entry) {
double latency;
- char buf1[128];
- char buf2[128];
+ char buf1[132];
+ char buf2[132];
latency = (double)(stop - start) / divisor;
latency -= (double)num_of_usecs_to_sleep;
break;
case DECR_TRAP:
- last_decrementer_kd = kd;
+ last_decrementer_kd[cpunum] = kd;
if (i_thresh_hold && (int)i_latency > i_thresh_hold)
p = "*";
ti->pathptr = (long *)0;
ti->child_thread = 0;
}
- if (!ti->pathptr) {
+ while ( (kd < end_of_sample) && ((kd->debugid & DBG_FUNC_MASK) == VFS_LOOKUP))
+ {
+ if (!ti->pathptr) {
ti->arg1 = kd->arg1;
memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
sargptr = (long *)&ti->pathname[0];
*sargptr++ = kd->arg4;
ti->pathptr = sargptr;
- } else {
+ } else {
sargptr = ti->pathptr;
/*
handle.
*/
- if ((long *)sargptr < (long *)&ti->pathname[PATHLENGTH])
+ if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
+ {
+ kd++;
+ continue;
+ }
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (kd->debugid & DBG_FUNC_START)
+ {
+ (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
+ }
+ else
{
*sargptr++ = kd->arg1;
*sargptr++ = kd->arg2;
*sargptr++ = kd->arg3;
*sargptr++ = kd->arg4;
ti->pathptr = sargptr;
+ }
+ }
+ kd++;
+ }
+
+ kd--;
/* print the tail end of the pathname */
- len = strlen(ti->pathname);
- if (len > 28)
- len -= 28;
- else
- len = 0;
+ len = strlen(ti->pathname);
+ if (len > 42)
+ len -= 42;
+ else
+ len = 0;
- if (log_fp) {
- fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s %-8x %-8x %d %s\n",
- timestamp - start_bias, delta, "VFS_LOOKUP",
- &ti->pathname[len], ti->arg1, thread, cpunum, command);
- }
- }
+ if (log_fp) {
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
+ timestamp - start_bias, delta, "VFS_LOOKUP",
+ &ti->pathname[len], ti->arg1, thread, cpunum, command);
}
+
last_timestamp = timestamp;
break;
kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency)
{
kd_buf *kd, *kd_start, *kd_stop;
+ int kd_count; /* Limit the boundary of kd_start */
double timestamp, last_timestamp, delta, start_bias;
int thread, cpunum;
int debugid, type, clen;
fprintf(log_fp, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
thread = kd_beg->arg5 & KDBG_THREAD_MASK;
+ cpunum = (kd_end->arg5 & KDBG_CPU_MASK) ? 1: 0;
- for (kd_start = kd_beg - 1; (kd_start >= (kd_buf *)my_buffer) && (kd_start->arg5 & KDBG_THREAD_MASK) == thread; kd_start--) {
- if ((kd_start->debugid & DBG_FUNC_MASK) == DECR_TRAP)
+ for (kd_count = 0, kd_start = kd_beg - 1; (kd_start >= (kd_buf *)my_buffer); kd_start--, kd_count++) {
+ if (kd_count == MAX_LOG_COUNT)
+ break;
+
+ if((kd_start->arg5 & KDBG_CPU_MASK) != cpunum)
+ continue;
+
+ if ((kd_start->debugid & DBG_FUNC_MASK) == DECR_TRAP)
+ break;
+
+ if((kd_start->arg5 & KDBG_THREAD_MASK) != thread)
break;
}
+
if (kd_start < (kd_buf *)my_buffer)
kd_start = (kd_buf *)my_buffer;
- for (kd_stop = kd_end + 1; kd_stop < end_of_sample && (kd_start->arg5 & KDBG_THREAD_MASK) == thread; kd_stop++) {
- if ((kd_stop->debugid & DBG_FUNC_MASK) == DECR_TRAP)
+ thread = kd_end->arg5 & KDBG_THREAD_MASK;
+
+ for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
+
+ if ((kd_stop->debugid & DBG_FUNC_MASK) == DECR_TRAP)
+ break;
+
+ if((kd_stop->arg5 & KDBG_CPU_MASK) != cpunum)
+ continue;
+
+ if((kd_stop->arg5 & KDBG_THREAD_MASK) != thread)
break;
}
+
if (kd_stop >= end_of_sample)
kd_stop = end_of_sample - 1;
ti->pathptr = (long *)0;
ti->child_thread = 0;
}
- if (!ti->pathptr) {
+
+ while ( (kd <= kd_stop) && (kd->debugid & DBG_FUNC_MASK) == VFS_LOOKUP)
+ {
+ if (!ti->pathptr) {
ti->arg1 = kd->arg1;
memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
sargptr = (long *)&ti->pathname[0];
*sargptr++ = kd->arg4;
ti->pathptr = sargptr;
- } else {
+ } else {
sargptr = ti->pathptr;
/*
handle.
*/
- if ((long *)sargptr < (long *)&ti->pathname[PATHLENGTH])
+ if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
+ {
+ kd++;
+ continue;
+ }
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (kd->debugid & DBG_FUNC_START)
+ {
+ (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
+ }
+ else
{
*sargptr++ = kd->arg1;
*sargptr++ = kd->arg2;
*sargptr++ = kd->arg3;
*sargptr++ = kd->arg4;
-
- /* print the tail end of the pathname */
- len = strlen(ti->pathname);
- if (len > 28)
- len -= 28;
- else
- len = 0;
-
- fprintf(log_fp, "%9.1f %8.1f\t\t%-28.28s %-28s %-8x %-8x %d %s\n",
- timestamp - start_bias, delta, "VFS_LOOKUP",
- &ti->pathname[len], ti->arg1, thread, cpunum, command);
+ ti->pathptr = sargptr;
}
+ }
+ kd++;
}
+
+ kd--;
+ /* print the tail end of the pathname */
+ len = strlen(ti->pathname);
+ if (len > 42)
+ len -= 42;
+ else
+ len = 0;
+
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
+ timestamp - start_bias, delta, "VFS_LOOKUP",
+ &ti->pathname[len], ti->arg1, thread, cpunum, command);
+
last_timestamp = timestamp;
break;
NEXTSTEP_INSTALLDIR = /usr/bin
WINDOWS_INSTALLDIR = /usr/bin
PDO_UNIX_INSTALLDIR = /usr/bin
-LIBS =
+LIBS = -lpam -lpam_misc
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
INSTALL_AS_USER = root
INSTALL_PERMISSIONS = 4555
-#CHFLAGS = /usr/bin/chflags
-#after_install::
-# $(CHFLAGS) schg $(DSTROOT)$(INSTALLDIR)/$(NAME)
+after_install:
+ mkdir -p "$(DSTROOT)/usr/share/man/man1"
+ install -c -m 644 login.1 "$(DSTROOT)/usr/share/man/man1/login.1"
CLEAN_ALL_SUBPROJECTS = YES
OTHER_GENERATED_OFILES = $(VERS_OFILE)
+OTHER_CFLAGS = -DUSE_PAM -no-cpp-precomp
+AFTER_INSTALL = after_install
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
+#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>
#include <utmp.h>
+#ifdef USE_PAM
+#include <pam/pam_appl.h>
+#include <pam/pam_misc.h>
+#endif
+
#include "pathnames.h"
void badlogin __P((char *));
struct passwd *pwd;
int failures;
-char term[64], *envinit[1], *hostname, *username, *tty;
+char term[64], *hostname, *username = NULL, *tty;
int
main(argc, argv)
struct stat st;
struct timeval tp;
struct utmp utmp;
- int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
+ int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin = 0, rval;
uid_t uid;
+ uid_t euid;
+ gid_t egid;
char *domain, *p, *salt, *ttyn;
char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
char localhost[MAXHOSTNAMELEN];
+#ifdef USE_PAM
+ pam_handle_t *pamh = NULL;
+ struct pam_conv conv = { misc_conv, NULL };
+ char **pmenv;
+ pid_t pid;
+#endif
(void)signal(SIGALRM, timedout);
(void)alarm(timeout);
syslog(LOG_ERR, "couldn't get local hostname: %m");
else
domain = strchr(localhost, '.');
+
+ euid = geteuid();
+ egid = getegid();
fflag = hflag = pflag = 0;
uid = getuid();
else
tty = ttyn;
+#ifdef USE_PAM
+ rval = pam_start("login", username, &conv, &pamh);
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+ rval = pam_set_item(pamh, PAM_TTY, tty);
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+
+ rval = pam_set_item(pamh, PAM_RHOST, hostname);
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+
+ rval = pam_set_item(pamh, PAM_USER_PROMPT, "login: ");
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+
+ if( !username )
+ getloginname();
+ pam_set_item(pamh, PAM_USER, username);
+ pwd = getpwnam(username);
+ if( (pwd != NULL) && (pwd->pw_uid == 0) )
+ rootlogin = 1;
+
+ if( (pwd != NULL) && fflag && ((uid == 0) || (uid == pwd->pw_uid)) ){
+ rval = 0;
+ } else {
+
+ rval = pam_authenticate(pamh, 0);
+ while( (cnt++ < 10) && ((rval == PAM_AUTH_ERR) ||
+ (rval == PAM_USER_UNKNOWN) ||
+ (rval == PAM_CRED_INSUFFICIENT) ||
+ (rval == PAM_AUTHINFO_UNAVAIL))) {
+ badlogin(username);
+ printf("Login incorrect\n");
+ rootlogin = 0;
+ getloginname();
+ pwd = getpwnam(username);
+ if( (pwd != NULL) && (pwd->pw_uid == 0) )
+ rootlogin = 1;
+ pam_set_item(pamh, PAM_USER, username);
+ rval = pam_authenticate(pamh, 0);
+ }
+
+ if( rval != PAM_SUCCESS ) {
+ pam_get_item(pamh, PAM_USER, (void *)&username);
+ badlogin(username);
+ printf("Login incorrect\n");
+ exit(1);
+ }
+
+ rval = pam_acct_mgmt(pamh, 0);
+ if( rval == PAM_NEW_AUTHTOK_REQD ) {
+ rval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ }
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+ }
+
+ rval = pam_get_item(pamh, PAM_USER, (void *)&username);
+ if( (rval == PAM_SUCCESS) && username && *username)
+ pwd = getpwnam(username);
+
+ rval = pam_open_session(pamh, 0);
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+
+ rval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if( rval != PAM_SUCCESS ) {
+ fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
+ exit(1);
+ }
+
+#else /* USE_PAM */
for (cnt = 0;; ask = 1) {
if (ask) {
fflag = 0;
sleep((u_int)((cnt - 3) * 5));
}
}
+#endif
/* committed to login -- turn off timeout */
(void)alarm((u_int)0);
if (!rootlogin)
checknologin();
+ setegid(pwd->pw_gid);
+ seteuid(rootlogin ? 0 : pwd->pw_uid);
+
+ /* First do a stat in case the homedir is automounted */
+\r stat(pwd->pw_dir,&st);
+
if (chdir(pwd->pw_dir) < 0) {
(void)printf("No home directory %s!\n", pwd->pw_dir);
if (chdir("/"))
pwd->pw_dir = "/";
(void)printf("Logging in with home = \"/\".\n");
}
+ seteuid(euid);
+ setegid(egid);
quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
- if (pwd->pw_change || pwd->pw_expire)
- (void)gettimeofday(&tp, (struct timezone *)NULL);
- if (pwd->pw_change)
- if (tp.tv_sec >= pwd->pw_change) {
- (void)printf("Sorry -- your password has expired.\n");
- sleepexit(1);
- } else if (pwd->pw_change - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
- (void)printf("Warning: your password expires on %s",
- ctime(&pwd->pw_change));
- if (pwd->pw_expire)
- if (tp.tv_sec >= pwd->pw_expire) {
- (void)printf("Sorry -- your account has expired.\n");
- sleepexit(1);
- } else if (pwd->pw_expire - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
- (void)printf("Warning: your account expires on %s",
- ctime(&pwd->pw_expire));
-
/* Nothing else left to fail -- really log in. */
memset((void *)&utmp, 0, sizeof(utmp));
(void)time(&utmp.ut_time);
pwd->pw_shell = _PATH_BSHELL;
/* Destroy environment unless user has requested its preservation. */
- if (!pflag)
- environ = envinit;
+ if (!pflag) {
+ environ = malloc(sizeof(char *));
+ *environ = NULL;
+ }
(void)setenv("HOME", pwd->pw_dir, 1);
(void)setenv("SHELL", pwd->pw_shell, 1);
if (term[0] == '\0')
(void)setenv("KRBTKFILE", krbtkfile_env, 1);
#endif
+#ifdef USE_PAM
+ pmenv = pam_getenvlist(pamh);
+ for( cnt = 0; pmenv && pmenv[cnt]; cnt++ )
+ putenv(pmenv[cnt]);
+
+ pid = fork();
+ if ( pid < 0 ) {
+ err(1, "fork");
+ } else if( pid != 0 ) {
+ waitpid(pid, NULL, 0);
+ pam_setcred(pamh, PAM_DELETE_CRED);
+ rval = pam_close_session(pamh, 0);
+ pam_end(pamh,rval);
+ exit(0);
+ }
+
+#endif
+
if (tty[sizeof("tty")-1] == 'd')
syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
}
#ifdef KERBEROS
-#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
+#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
#else
-#define NBUFSIZ (UT_NAMESIZE + 1)
+#define NBUFSIZ (MAXLOGNAME + 1)
#endif
void
if (p < nbuf + (NBUFSIZ - 1))
*p++ = ch;
}
- if (p > nbuf)
+ if (p > nbuf) {
if (nbuf[0] == '-')
(void)fprintf(stderr,
"login names may not start with '-'.\n");
username = nbuf;
break;
}
+ }
}
}
#
-# Generated by the NeXT Project Builder.
+# Generated by the Apple Project Builder.
#
# NOTE: Do NOT change this file -- Project Builder maintains it.
#
PROJECTVERSION = 2.8
PROJECT_TYPE = Tool
-HFILES = bootstrap_internal.h error_log.h lists.h parser.h
+HFILES = bootstrap_internal.h error_log.h lists.h
-CFILES = bootstrap.c error_log.c lists.c parser.c rpc_services.c
+CFILES = bootstrap.c error_log.c lists.c rpc_services.c
-OTHERSRCS = Makefile.preamble Makefile initConf Notes testConfig\
- testConfig2 bootstrap.defs testServer
+OTHERSRCS = Makefile.preamble Makefile bootstrap.defs mach_init.8\
+ Makefile.postamble
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS = 4555
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+
+install-man-page:
+ install -d $(DSTROOT)/usr/share/man/man8
+ install -c -m 444 mach_init.8 $(DSTROOT)/usr/share/man/man8/mach_init.8
OTHER_GENERATED_OFILES = $(VERS_OFILE)
BEFORE_BUILD += bootstrap.h
OTHER_OFILES = bootstrapServer.o
-
+AFTER_INSTALL += install-man-page
+++ /dev/null
-# gvdl@next 3 Aug 1995
-# Need to get the bootstrap .defs stuff working properly
-
-Format of /etc/bootstrap.conf
-
-[[restartable] (server|init) "SERVER_PATH ARGS"] [services { SERVICE_NAME
- [, SERVICE_NAME]* }]
-
-struct service {
- struct service *next;
- struct service *prev;
- char *name;
- port_t port;
- struct server *server;
- struct service *server_link;
-};
-
-struct server {
- struct server *next;
- struct server *prev;
- boolean_t restartable;
- boolean_t isEtcInit;
- char **argv;
- struct service *services;
-};
-
-Service entries create service-port pairs. Lookup rpc's return send rights. Checkin rpc's return all rights. Checkin's can only be done from "privileged" bootstrap ports (see server, below). Bootstrap is the default backup for service ports, if bootstrap receives the port back, it holds onto all rights (to give out on a later checkin), and marks the service inactive. Lookup's on inactive services continue to return the service port. Lookup's on unregistered services return PORT_NULL.
-
-Server entries initiate server tasks. Server tasks receive a privileged bootstrap port that allows the server task to register new service-port pairs and perform checkin's. Servers can obtain an unprivileged lookup/status-only port with an rpc; that port should be passed to untrusted progeny. Servers are initiated in the order that they appear in bootstrap.conf. Restartable servers are re-initiated if port destroyed or port deleted notification is received for all of the service ports declared by that server in bootstrap.conf. On restart, a server may reobtain receive rights for service ports that were returned to bootstrap via the port backup mechanism. New ports for are created for declared service ports without back-up when bootstrap receives a port deleted notification. If bootstrap receives a port deleted notification for a registered, but undeclared service port, further lookups on that name return PORT_NULL. Runtime registered ports are not associated with a server and are not involved in restart determination. Rights for registered ports that specify bootstrap as backup will be held and may later be transfered to a new server instantiation via the checkin. Should a new server instantiation re-register the service, the port and associated receive rights will be deallocated.
-
-There may only be a single init entry; it is a special server entry and provides a (hack) mechanism to allow /etc/init to be exec'ed as pid 1. In the longer run, bootstrap should take over system shutdown/reconfig responsibilities and this won't be necessary.
-
-As a compatability hack, the initial version of bootstrap will initialize the ports inherited on task_create() via mach_ports_register(). Existing services utilizing service_checkin() will have to be modified to use bootstrap_checkin().
-
-Bootstrap rpc's:
-
-bootstrap_checkin(port_t priv_bootstrap_port, char *service_name,
- port *service_port);
-
- Returns receive rights in service_port for service named by service_name.
- FIXME: Success/Failure indication???
-
-bootstrap_register(port_t priv_bootstrap_port, char *service_name,
- port service_port);
-
- Registers service_name -- service_port pair.
- FIXME: Success/Failure indication???
-
-bootstrap_checkout(port_t priv_bootstrap_port, char *service_name);
-
- Removes registration for service named by service_name.
- Fails is service is currently active.
- FIXME: Success/Failure indication???
-
-bootstrap_lookup(port_t bootstrap_port, char *service_name, port_t service_port);
-
- Returns service port for service named by service_name.
-
-bootstrap_lookup_array(port_t bootstrap_port, name_array_t service_names, port_array_t service_ports, int service_count);
-
- Returns service ports for all services named in service_names array.
-
-boostrap_status(port_t bootstrap_port, name_array_t service_names,
- bool_array_t service_actives, int *service_count);
-
- Returns names and active status for all known services.
-
-bootstrap_get_unpriv_port(port_t bootstrap_port, port_t *unpriv_bootstrap_port);
-
- Returns the unprivileged bootstrap service port.
-
FILESTABLE = {
BUNDLES = ();
CLASSES = ();
- C_FILES = ();
+ "C_FILES" = ();
FRAMEWORKS = ();
FRAMEWORKSEARCH = ();
HEADERSEARCH = ();
- H_FILES = (bootstrap_internal.h, error_log.h, lists.h, parser.h);
- M_FILES = ();
- OTHER_LIBS = ();
- OTHER_LINKED = (bootstrap.c, error_log.c, lists.c, parser.c, rpc_services.c);
- OTHER_SOURCES = (
- Makefile.preamble,
+ "H_FILES" = ("bootstrap_internal.h", "error_log.h", "lists.h");
+ "M_FILES" = ();
+ "OTHER_LIBS" = ();
+ "OTHER_LINKED" = ("bootstrap.c", "error_log.c", "lists.c", "rpc_services.c");
+ "OTHER_SOURCES" = (
+ "Makefile.preamble",
Makefile,
- initConf,
- Notes,
- testConfig,
- testConfig2,
- bootstrap.defs,
- testServer
+ "bootstrap.defs",
+ "mach_init.8",
+ "Makefile.postamble"
);
SUBPROJECTS = ();
TOOLS = ();
};
LANGUAGE = English;
- LOCALIZABLE_FILES = {};
- NEXTSTEP_BUILDDIR = "/tmp/$(USER)/BUILD";
- NEXTSTEP_BUILDTOOL = /bin/gnumake;
- NEXTSTEP_COMPILEROPTIONS = "-DMACH_USER_API";
- NEXTSTEP_INSTALLDIR = /sbin;
- NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
- NEXTSTEP_MAINNIB = mach_init;
- NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
- PDO_UNIX_COMPILEROPTIONS = "-DMACH_USER_API";
- PDO_UNIX_INSTALLDIR = /sbin;
- PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac";
- PDO_UNIX_MAINNIB = mach_init;
- PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = mach_init;
+ "LOCALIZABLE_FILES" = {};
+ "NEXTSTEP_BUILDDIR" = "/tmp/$(USER)/BUILD";
+ "NEXTSTEP_BUILDTOOL" = "/bin/gnumake";
+ "NEXTSTEP_COMPILEROPTIONS" = "-DMACH_USER_API";
+ "NEXTSTEP_INSTALLDIR" = "/sbin";
+ "NEXTSTEP_JAVA_COMPILER" = "/usr/bin/javac";
+ "NEXTSTEP_MAINNIB" = "mach_init";
+ "NEXTSTEP_OBJCPLUS_COMPILER" = "/usr/bin/cc";
+ "PDO_UNIX_COMPILEROPTIONS" = "-DMACH_USER_API";
+ "PDO_UNIX_INSTALLDIR" = "/sbin";
+ "PDO_UNIX_JAVA_COMPILER" = "$(NEXTDEV_BIN)/javac";
+ "PDO_UNIX_MAINNIB" = "mach_init";
+ "PDO_UNIX_OBJCPLUS_COMPILER" = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = "mach_init";
PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_COMPILEROPTIONS = "-DMACH_USER_API";
- WINDOWS_INSTALLDIR = /sbin;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_MAINNIB = mach_init;
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+ PROJECTVERSION = "2.8";
+ "WINDOWS_COMPILEROPTIONS" = "-DMACH_USER_API";
+ "WINDOWS_INSTALLDIR" = "/sbin";
+ "WINDOWS_JAVA_COMPILER" = "$(JDKBINDIR)/javac.exe";
+ "WINDOWS_MAINNIB" = "mach_init";
+ "WINDOWS_OBJCPLUS_COMPILER" = "$(DEVDIR)/gcc";
}
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <mach/exception.h>
#import <sys/ioctl.h>
+#import <sys/types.h>
+#import <sys/wait.h>
+#import <pthread.h>
#import <string.h>
#import <ctype.h>
#import <stdio.h>
#import <libc.h>
-#include "bootstrap.h"
+#import "bootstrap.h"
#import "bootstrap_internal.h"
#import "lists.h"
#import "error_log.h"
-#import "parser.h"
/* Mig should produce a declaration for this, but doesn't */
extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
*/
const char *program_name; /* our name for error messages */
-#ifndef CONF_FILE
-#define CONF_FILE "/etc/bootstrap.conf" /* default config file */
-#endif CONF_FILE
-
-const char *conf_file = CONF_FILE;
-
-const unsigned BOOTSTRAP_REPLY_TIMEOUT = 10 * 1000; // 10 sec reply timeout
-#ifdef notyet
-port_all_t backup_port;
-#endif /* notyet */
-/*
- * Last resort configuration
- *
- * If we can't find a /etc/bootstrap.conf, we use this configuration.
- * The services defined here are compatable with the old mach port stuff,
- * and of course, the names for these services should not be modified without
- * modifying mach_init in libc.
- */
-const char *default_conf =
- "init \"/sbin/init\";"
- "services NetMessage;";
+#ifndef INIT_PATH
+#define INIT_PATH "/sbin/init" /* default init path */
+#endif INIT_PATH
+uid_t inherited_uid;
mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
boolean_t forward_ok = FALSE;
+boolean_t shutdown_in_progress = FALSE;
boolean_t debugging = FALSE;
boolean_t register_self = FALSE;
-int init_priority = BASEPRI_USER;
-char *register_name = NULL;
-mach_port_t bootstrap_master_device_port; /* local name */
-mach_port_t bootstrap_master_host_port; /* local name */
-mach_port_t bootstrap_notification_port; /* local name */
-mach_port_t security_port;
-mach_port_t root_ledger_wired;
-mach_port_t root_ledger_paged;
-task_port_t bootstrap_self;
+boolean_t force_fork = FALSE;
+const char *register_name;
+task_t bootstrap_self;
#ifndef ASSERT
#define ASSERT(p)
/*
* Private declarations
*/
-static void add_init_arg(const char *arg);
static void wait_for_go(mach_port_t init_notify_port);
static void init_ports(void);
static void start_server(server_t *serverp);
-static void unblock_init(task_port_t task, mach_port_t newBootstrap);
+static void unblock_init(mach_port_t init_notify_port, mach_port_t newBootstrap);
static void exec_server(server_t *serverp);
static char **argvize(const char *string);
+static void *demand_loop(void *arg);
static void server_loop(void);
-static void msg_destroy(mach_msg_header_t *m);
+extern kern_return_t bootstrap_register
+(
+ mach_port_t bootstrap_port,
+ name_t service_name,
+ mach_port_t service_port
+);
/*
* Private ports we hold receive rights for. We also hold receive rights
* structs.
*/
mach_port_t bootstrap_port_set;
+mach_port_t demand_port_set;
+pthread_t demand_thread;
+
mach_port_t notify_port;
+mach_port_t backup_port;
-static int init_pid;
-static int running_servers;
-static char init_args[BOOTSTRAP_MAX_CMD_LEN];
+static void
+notify_server_loop(mach_port_name_t about)
+{
+ mach_port_destroyed_notification_t not;
+ mach_msg_return_t nresult;
+
+ not.not_header.msgh_id = DEMAND_REQUEST;
+ not.not_header.msgh_remote_port = backup_port;
+ not.not_header.msgh_local_port = MACH_PORT_NULL;
+ not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
+ not.not_header.msgh_size = sizeof(not) - sizeof(not.trailer);
+ not.not_body.msgh_descriptor_count = 1;
+ not.not_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME;
+ not.not_port.name = about;
+ nresult = mach_msg_send(¬.not_header);
+ if (nresult != MACH_MSG_SUCCESS) {
+ kern_error(nresult, "notify_server: mach_msg_send()");
+ }
+}
void _myExit(int arg)
{
exit(arg);
}
-/* It was a bozo who made main return a value! Civil disobedience, here. */
-void
-main(int argc, const char * const argv[])
+void toggle_debug(int signal)
+{
+ debugging = (debugging) ? FALSE : TRUE;
+}
+
+void start_shutdown(int signal)
+{
+ debug("received SIGTERM");
+ shutdown_in_progress = TRUE;
+ notify_server_loop(MACH_PORT_DEAD);
+}
+
+int
+main(int argc, char * argv[])
{
const char *argp;
char c;
- server_t *init_serverp;
server_t *serverp;
- mach_port_t init_notify_port;
kern_return_t result;
+ mach_port_t init_notify_port;
+ pthread_attr_t attr;
+ sigset_t mask;
int pid;
- int force_fork = FALSE;
- mach_port_t prev_port;
-#if defined(__APPLE__)
- extern void exit(int);
-
- /* signal (SIGUSR2, _myExit); */
-#endif
+
+ /*
+ * If we are pid one, we have to exec init. Before doing so, we'll
+ * fork a child, and that will become the true mach_init. But we have
+ * to be very careful about ports. They aren't inherited across fork,
+ * so we have to avoid storing port names in memory before the fork that
+ * might not be valid after.
+ */
+ pid = getpid();
+ if (pid == 1)
+ {
+ close(0);
+ freopen("/dev/console", "r", stdin);
+ setbuf(stdin, NULL);
+ close(1);
+ freopen("/dev/console", "w", stdout);
+ setbuf(stdout, NULL);
+ close(2);
+ freopen("/dev/console", "w", stderr);
+ setbuf(stderr, NULL);
+
+ result = mach_port_allocate(
+ mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &init_notify_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_allocate");
+
+ result = mach_port_insert_right(
+ mach_task_self(),
+ init_notify_port,
+ init_notify_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_insert_right");
+
+ result = task_set_bootstrap_port(
+ mach_task_self(),
+ init_notify_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "task_set_bootstrap_port");
+
+ pid = fork();
+
+ if (pid < 0)
+ unix_fatal("fork");
+
+ else if (pid != 0) { /* PARENT - will become init when ready */
+ int fd;
+
+ /*
+ * Wait for mach_init ot give us a real bootstrap port
+ */
+ wait_for_go(init_notify_port);
+ info("Execing init");
+
+ close(0);
+ close(1);
+ close(2);
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd >= 0) {
+ ioctl(fd, TIOCNOTTY, 0);
+ close(fd);
+ }
+
+ /* pass our arguments on to init */
+ argv[0] = INIT_PATH;
+ execv(argv[0], argv);
+ exit(1); /* will likely trigger a panic */
+
+ }
+ } else
+ init_notify_port = MACH_PORT_NULL;
/* Initialize error handling */
program_name = rindex(*argv, '/');
program_name = *argv;
argv++; argc--;
- init_pid = getpid();
- init_errlog(init_pid == 1);
-
- /*
- * Get master host and device ports
- */
-#if 0
- result = bootstrap_ports(bootstrap_port,
- &bootstrap_master_host_port,
- &bootstrap_master_device_port,
- &root_ledger_wired,
- &root_ledger_paged,
- &security_port);
- if (result != KERN_SUCCESS) {
- printf("bootstrap_ports failed \n");
- kern_error(result, "bootstrap_ports");
- }
-#endif /* 0 */
- /*
- * This task will become the bootstrap task.
- */
- bootstrap_self = mach_task_self();
-
- /* Initialize globals */
- init_lists();
-
/* Parse command line args */
while (argc > 0 && **argv == '-') {
- boolean_t init_arg = FALSE;
argp = *argv++ + 1; argc--;
while (*argp) {
switch (c = *argp++) {
case 'F':
force_fork = TRUE;
break;
- case 'f':
- if (argc > 0) {
- conf_file = *argv++; argc--;
- } else
- fatal("-f requires config file name");
- break;
- case '-':
- init_arg = TRUE;
- break;
case 'r':
register_self = forward_ok = TRUE;
if (argc > 0) {
} else
fatal("-r requires name");
break;
+ case '-':
default:
- init_arg = TRUE;
break;
}
}
- if (init_arg) {
- add_init_arg(argv[-1]);
- goto copyargs;
- }
- }
- copyargs:
- while (argc != 0) {
- argc--;
- add_init_arg(*argv++);
}
- log("Started");
-
- /* Parse the config file */
- init_config();
-
- /* set_default_policy(bootstrap_master_host_port); */
-
/*
- * If we have to run init as pid 1, use notify port to
- * synchronize init and bootstrap
+ * If we must fork, do it now before we get Mach ports in use
*/
- if ((init_serverp = find_init_server()) != NULL) {
- if (init_pid != 1 && ! debugging)
- fatal("Can't start init server if not pid 1");
- result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
- &init_notify_port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_allocate");
- result = mach_port_insert_right(mach_task_self(), init_notify_port, init_notify_port, MACH_MSG_TYPE_MAKE_SEND);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_insert_right");
- task_set_bootstrap_port(bootstrap_self, init_notify_port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "task_set_bootstrap_port");
- /*
- * XXX restart the service if it dies?
- */
- result = mach_port_request_notification(mach_task_self(),
- mach_task_self(),
- MACH_NOTIFY_DEAD_NAME,
- 0,
- init_notify_port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &prev_port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_request_notification");
- debug("Set port %d for parent proc notify port",
- init_notify_port);
- } else if (init_args[0] != '\0')
- fatal("Extraneous command line arguments");
-
- /* Fork if either not debugging or running /etc/init */
- if (force_fork || !debugging || init_serverp != NULL) {
+ if (force_fork) {
pid = fork();
if (pid < 0)
unix_fatal("fork");
- } else
- pid = 0;
+ else if (pid != 0) /* PARENT: just exit */
+ exit(0);
+ }
+
+ /* block all but SIGHUP and SIGTERM and mark us as an init process */
+ setsid();
+ sigfillset(&mask);
+ sigdelset(&mask, SIGHUP);
+ signal(SIGHUP, toggle_debug);
+ sigdelset(&mask, SIGTERM);
+ signal(SIGTERM, start_shutdown);
+ (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
+
+ init_errlog(pid == 0); /* are we a daemon? */
+ init_lists();
+
+ /*
+ * This task will become the bootstrap task, so go ahead and
+ * initialize the ports now.
+ */
+ bootstrap_self = mach_task_self();
+ inherited_uid = getuid();
+ init_ports();
- /* Bootstrap service runs in child (if there is one) */
- if (pid == 0) { /* CHILD */
- /*
- * If we're initiated by pid 1, we shouldn't get ever get
- * killed; designate ourselves as an "init process".
- *
- * This should go away with new signal stuff!
- */
- if (init_pid == 1)
- init_process();
+ log("Started with uid=%d%s%s%s",
+ inherited_uid,
+ (register_self) ? " registered-as=" : "",
+ (register_self) ? register_name : "",
+ (debugging) ? " in debug-mode" : "");
- /* Create declared service ports, our service port, etc */
- init_ports();
- /* Kick off all server processes */
- for ( serverp = FIRST(servers)
- ; !IS_END(serverp, servers)
- ; serverp = NEXT(serverp))
- start_server(serverp);
-
- /*
- * If our priority's to be changed, set it up here.
- */
-#ifdef notyet
- if (init_priority >= 0) {
- result = task_priority(mach_task_self(), init_priority,
- TRUE);
+ /*
+ * If we are supposed to coordinate with init, we have to
+ * get that port again, because we only have a (probably wrong)
+ * name in memory, not a proper right.
+ */
+ if (init_notify_port != MACH_PORT_NULL) {
+ result = task_get_bootstrap_port(
+ bootstrap_self,
+ &init_notify_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "task_get_bootstrap_port");
+
+ unblock_init(init_notify_port, bootstraps.bootstrap_port);
+
+ result = task_set_bootstrap_port(
+ bootstrap_self,
+ MACH_PORT_NULL);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "task_set_bootstrap_port");
+
+ result = mach_port_deallocate(
+ bootstrap_self,
+ init_notify_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_deallocate");
+
+ forward_ok = FALSE;
+ inherited_bootstrap_port = MACH_PORT_NULL;
+
+ } else {
+
+ /* get inherited bootstrap port */
+ result = task_get_bootstrap_port(
+ bootstrap_self,
+ &inherited_bootstrap_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "task_get_bootstrap_port");
+
+ /* We set this explicitly as we start each child */
+ task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
+ if (inherited_bootstrap_port == MACH_PORT_NULL)
+ forward_ok = FALSE;
+
+ /* register "self" port with anscestor */
+ if (register_self && forward_ok) {
+ result = bootstrap_register(
+ inherited_bootstrap_port,
+ (char *)register_name,
+ bootstraps.bootstrap_port);
if (result != KERN_SUCCESS)
- kern_error(result, "task_priority %d",
- init_priority);
+ kern_fatal(result, "register self");
}
-#endif /* notyet */
- /* Process bootstrap service requests */
- server_loop(); /* Should never return */
- exit(1);
}
-
- /* PARENT */
- if (init_serverp != NULL) {
- int i;
- strncat(init_serverp->cmd,
- init_args,
- sizeof(init_serverp->cmd));
- /*
- * Wait, then either exec /etc/init or exit
- * (which panics the system)
- */
- for (i = 3; i; i--)
- close(i);
- wait_for_go(init_notify_port);
- exec_server(init_serverp);
+
+ /* Kick off all continuously running server processes */
+ for ( serverp = FIRST(servers)
+ ; !IS_END(serverp, servers)
+ ; serverp = NEXT(serverp))
+ if (serverp->servertype != DEMAND)
+ start_server(serverp);
+
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
+ result = pthread_create(
+ &demand_thread,
+ &attr,
+ demand_loop,
+ NULL);
+ if (result) {
+ unix_error("pthread_create()");
exit(1);
}
- exit(0);
-}
-static void
-add_init_arg(const char *arg)
-{
- strncat(init_args, " ", sizeof(init_args));
- strncat(init_args, arg, sizeof(init_args));
+ /* Process bootstrap service requests */
+ server_loop(); /* Should never return */
+ exit(1);
}
static void
wait_for_go(mach_port_t init_notify_port)
{
- struct {
+ struct {
mach_msg_header_t hdr;
mach_msg_trailer_t trailer;
- } init_go_msg;
+ } init_go_msg;
kern_return_t result;
- /*
+ /*
* For now, we just blindly wait until we receive a message or
* timeout. We don't expect any notifications, and if we get one,
* it probably means something dire has happened; so we might as
* well give a shot at letting init run.
*/
- result = mach_msg(&init_go_msg.hdr, MACH_RCV_MSG, 0, sizeof(init_go_msg), init_notify_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
- if (result != KERN_SUCCESS) {
- kern_error(result, "mach_msg(receive) failed in wait_for_go");
- }
- result = task_set_bootstrap_port(mach_task_self(), init_go_msg.hdr.msgh_remote_port);
- if (result != KERN_SUCCESS) {
- kern_error(result, "task_get_bootstrap_port()");
- }
+ result = mach_msg(
+ &init_go_msg.hdr, MACH_RCV_MSG,
+ 0, sizeof(init_go_msg), init_notify_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (result != KERN_SUCCESS) {
+ kern_error(result, "mach_msg(receive) failed in wait_for_go");
+ }
+ result = task_set_bootstrap_port(
+ mach_task_self(),
+ init_go_msg.hdr.msgh_remote_port);
+ if (result != KERN_SUCCESS) {
+ kern_error(result, "task_get_bootstrap_port()");
+ }
}
+
+static void
+unblock_init(mach_port_t init_notify_port,
+ mach_port_t newBootstrap)
+{
+ mach_msg_header_t init_go_msg;
+ kern_return_t result;
+
+ /*
+ * Proc 1 is blocked in a msg_receive on its notify port, this lets
+ * it continue, and we hand off its new bootstrap port
+ */
+ init_go_msg.msgh_remote_port = init_notify_port;
+ init_go_msg.msgh_local_port = newBootstrap;
+ init_go_msg.msgh_bits = MACH_MSGH_BITS(
+ MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND);
+ init_go_msg.msgh_size = sizeof(init_go_msg);
+ result = mach_msg_send(&init_go_msg);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "unblock_init mach_msg_send() failed");
+ debug("sent go message");
+}
+
+
static void
init_ports(void)
{
kern_return_t result;
service_t *servicep;
- mach_port_name_t previous;
- mach_port_t pport;
/*
* This task will become the bootstrap task.
*/
- bootstrap_self = mach_task_self();
-
- /* get inherited bootstrap port */
- result = task_get_bootstrap_port(bootstrap_self,
- &inherited_bootstrap_port);
+ /* Create port set that server loop listens to */
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_PORT_SET,
+ &bootstrap_port_set);
if (result != KERN_SUCCESS)
- kern_fatal(result, "task_get_bootstrap_port");
+ kern_fatal(result, "port_set_allocate");
- /* We set this explicitly as we start each child */
- task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
- if (inherited_bootstrap_port == MACH_PORT_NULL)
- forward_ok = FALSE;
-
- /* Create port set that server loop listens to */
- result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_PORT_SET,
- &bootstrap_port_set);
+ /* Create demand port set that second thread listens to */
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_PORT_SET,
+ &demand_port_set);
if (result != KERN_SUCCESS)
kern_fatal(result, "port_set_allocate");
+
/* Create notify port and add to server port set */
- result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
- ¬ify_port);
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_RECEIVE,
+ ¬ify_port);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_allocate");
- result = mach_port_request_notification(bootstrap_self,
+ result = mach_port_move_member(
bootstrap_self,
- MACH_NOTIFY_DEAD_NAME,
- 0,
notify_port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &pport);
+ bootstrap_port_set);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_move_member");
+
+ /* Create backup port and add to server port set */
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_RECEIVE,
+ &backup_port);
if (result != KERN_SUCCESS)
- kern_fatal(result, "task_set_notify_port");
+ kern_fatal(result, "mach_port_allocate");
- result = mach_port_move_member(bootstrap_self,
- notify_port,
- bootstrap_port_set);
+ result = mach_port_move_member(
+ bootstrap_self,
+ backup_port,
+ bootstrap_port_set);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_move_member");
/* Create "self" port and add to server port set */
- result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
- &bootstraps.bootstrap_port);
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_RECEIVE,
+ &bootstraps.bootstrap_port);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_allocate");
- result = mach_port_insert_right(mach_task_self(), bootstraps.bootstrap_port, bootstraps.bootstrap_port, MACH_MSG_TYPE_MAKE_SEND);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_insert_right");
- result = mach_port_move_member(bootstrap_self,
- bootstraps.bootstrap_port,
- bootstrap_port_set);
+ result = mach_port_insert_right(
+ bootstrap_self,
+ bootstraps.bootstrap_port,
+ bootstraps.bootstrap_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_insert_right");
+
+ /* keep the root bootstrap port "active" */
+ bootstraps.requestor_port = bootstraps.bootstrap_port;
+
+ result = mach_port_move_member(
+ bootstrap_self,
+ bootstraps.bootstrap_port,
+ bootstrap_port_set);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_move_member");
-#ifdef notyet
- /* register "self" port with anscestor */
- if (register_self && forward_ok) {
- result = bootstrap_register(inherited_bootstrap_port, register_name, bootstraps.bootstrap_port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "register self");
- }
-#endif /* notyet*/
+
/*
* Allocate service ports for declared services.
*/
{
switch (servicep->servicetype) {
case DECLARED:
- result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
- &(servicep->port));
+ result = mach_port_allocate(
+ bootstrap_self,
+ MACH_PORT_RIGHT_RECEIVE,
+ &(servicep->port));
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_allocate");
- result = mach_port_insert_right(bootstrap_self, servicep->port, servicep->port, MACH_MSG_TYPE_MAKE_SEND);
+
+ result = mach_port_insert_right(
+ bootstrap_self,
+ servicep->port,
+ servicep->port,
+ MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_insert_right");
- debug("Declared port %d for service %s",
+ info("Declared port %x for service %s",
servicep->port,
servicep->name);
-#ifdef notyet
- result = port_set_backup(task_self(),
- servicep->port,
- backup_port,
- &previous);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "port_set_backup");
-#endif /* notyet */
+
+ if (servicep->server != NULL_SERVER &&
+ servicep->server->servertype == DEMAND) {
+ result = mach_port_move_member(
+ bootstrap_self,
+ servicep->port,
+ demand_port_set);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_move_member");
+ }
break;
+
case SELF:
servicep->port = bootstraps.bootstrap_port;
- servicep->server = new_server(MACHINIT,
- program_name, init_priority);
- info("Set port %d for self port",
+ servicep->server = new_server(&bootstraps,
+ program_name,
+ inherited_uid,
+ MACHINIT);
+ info("Set port %x for self port",
bootstraps.bootstrap_port);
break;
+
case REGISTERED:
fatal("Can't allocate REGISTERED port!?!");
break;
}
}
+boolean_t
+active_bootstrap(bootstrap_info_t *bootstrap)
+{
+ return (bootstrap->requestor_port != MACH_PORT_NULL);
+}
+
+boolean_t
+useless_server(server_t *serverp)
+{
+ return ( !active_bootstrap(serverp->bootstrap) ||
+ !lookup_service_by_server(serverp) ||
+ !serverp->activity);
+}
+
+boolean_t
+active_server(server_t *serverp)
+{
+ return (
+#ifdef DELAYED_BOOTSTRAP_DESTROY
+ serverp->port ||
+#else
+ (serverp->port && serverp->pid == NO_PID) ||
+#endif
+ serverp->task_port || serverp->active_services);
+}
+
static void
-start_server(server_t *serverp)
+reap_server(server_t *serverp)
+{
+ kern_return_t result;
+ pid_t presult;
+ int wstatus;
+
+ /*
+ * Reap our children.
+ */
+ presult = waitpid(serverp->pid, &wstatus, WNOHANG);
+ if (presult != serverp->pid) {
+ unix_error("waitpid: cmd = %s", serverp->cmd);
+ } else if (wstatus) {
+ log("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
+ serverp->port, serverp->bootstrap->bootstrap_port,
+ serverp->uid, serverp->cmd,
+ ((WIFEXITED(wstatus)) ?
+ "exited with non-zero status" :
+ "exited as a result of signal"),
+ ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : WTERMSIG(wstatus)),
+ serverp->pid);
+ }
+ serverp->pid = 0;
+
+ /*
+ * Release the server task port reference, if we ever
+ * got it in the first place.
+ */
+ if (serverp->task_port != MACH_PORT_NULL) {
+ result = mach_port_deallocate(
+ mach_task_self(),
+ serverp->task_port);
+ if (result != KERN_SUCCESS)
+ kern_error(result, "mach_port_deallocate");
+ serverp->task_port = MACH_PORT_NULL;
+ }
+}
+
+static void
+demand_server(server_t *serverp)
+{
+ service_t *servicep;
+ kern_return_t result;
+
+ /*
+ * For on-demand servers, make sure that the service ports are
+ * back in on-demand portset. Active service ports should come
+ * back through a PORT_DESTROYED notification. We only have to
+ * worry about the inactive ports that may have been previously
+ * pulled from the set but never checked-in by the server.
+ */
+
+ for ( servicep = FIRST(services)
+ ; !IS_END(servicep, services)
+ ; servicep = NEXT(servicep))
+ {
+ if (serverp == servicep->server && !servicep->isActive) {
+ result = mach_port_move_member(
+ mach_task_self(),
+ servicep->port,
+ demand_port_set);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_move_member");
+ }
+ }
+}
+
+static
+void dispatch_server(server_t *serverp)
+{
+ if (!active_server(serverp)) {
+ if (useless_server(serverp))
+ delete_server(serverp);
+ else if (serverp->servertype == RESTARTABLE)
+ start_server(serverp);
+ else if (serverp->servertype == DEMAND)
+ demand_server(serverp);
+ }
+}
+
+void
+setup_server(server_t *serverp)
{
kern_return_t result;
mach_port_t old_port;
- task_port_t init_task;
- int pid;
- /* get rid of any old server port (this might be a restart) */
- old_port = serverp->port;
- serverp->port = MACH_PORT_NULL;
- if (old_port != MACH_PORT_NULL) {
- msg_destroy_port(old_port);
- }
/* Allocate privileged port for requests from service */
- result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE ,&serverp->port);
- info("Allocating port %d for server %s", serverp->port, serverp->cmd);
+ result = mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE ,
+ &serverp->port);
+ info("Allocating port %x for server %s", serverp->port, serverp->cmd);
if (result != KERN_SUCCESS)
kern_fatal(result, "port_allocate");
- result = mach_port_insert_right(mach_task_self(), serverp->port, serverp->port, MACH_MSG_TYPE_MAKE_SEND);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_insert_right");
+ /* Request no-senders notification so we can tell when server dies */
+ result = mach_port_request_notification(mach_task_self(),
+ serverp->port,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ serverp->port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_request_notification");
+
/* Add privileged server port to bootstrap port set */
result = mach_port_move_member(mach_task_self(),
- serverp->port,
- bootstrap_port_set);
+ serverp->port,
+ bootstrap_port_set);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_move_member");
+}
+
+static void
+start_server(server_t *serverp)
+{
+ kern_return_t result;
+ mach_port_t old_port;
+ int pid;
/*
* Do what's appropriate to get bootstrap port setup in server task
*/
switch (serverp->servertype) {
- case ETCINIT:
- /*
- * This is pid 1 init program -- need to punch stuff
- * back into pid 1 task rather than create a new task
- */
- result = task_for_pid(mach_task_self(), init_pid, &init_task);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "task_for_pid");
- serverp->task_port = init_task;
- unblock_init(init_task, serverp->port);
- break;
case MACHINIT:
break;
case SERVER:
+ case DEMAND:
case RESTARTABLE:
+#ifdef DELAYED_BOOTSTRAP_DESTROY
+ if (!serverp->port)
+#endif
+ setup_server(serverp);
+
+ serverp->activity = 0;
+
+ /* Insert a send right */
+ result = mach_port_insert_right(mach_task_self(),
+ serverp->port,
+ serverp->port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_insert_right");
+
/* Give trusted service a unique bootstrap port */
- result = task_set_bootstrap_port(mach_task_self(), serverp->port);
+ result = task_set_bootstrap_port(mach_task_self(),
+ serverp->port);
if (result != KERN_SUCCESS)
kern_fatal(result, "task_set_bootstrap_port");
+ result = mach_port_deallocate(mach_task_self(),
+ serverp->port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_deallocate");
+
pid = fork();
- if (pid < 0)
+ if (pid < 0) {
unix_error("fork");
- else if (pid == 0) { /* CHILD */
+ } else if (pid == 0) { /* CHILD */
exec_server(serverp);
exit(1);
} else { /* PARENT */
- result = task_set_bootstrap_port(mach_task_self(),
- MACH_PORT_NULL);
+
+ result = task_set_bootstrap_port(
+ mach_task_self(),
+ MACH_PORT_NULL);
if (result != KERN_SUCCESS)
kern_fatal(result, "task_set_bootstrap_port");
- result = task_for_pid(mach_task_self(),
- pid,
- &serverp->task_port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "getting server task port");
- running_servers += 1;
+ info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
+ serverp->port, serverp->bootstrap->bootstrap_port,
+ serverp->uid, serverp->cmd, pid);
+ serverp->pid = pid;
+ result = task_for_pid(
+ mach_task_self(),
+ pid,
+ &serverp->task_port);
+ if (result != KERN_SUCCESS) {
+ kern_error(result, "getting server task port");
+ reap_server(serverp);
+ dispatch_server(serverp);
+ break;
+ }
+
+ /* Request dead name notification to tell when task dies */
+ result = mach_port_request_notification(
+ mach_task_self(),
+ serverp->task_port,
+ MACH_NOTIFY_DEAD_NAME,
+ 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old_port);
+ if (result != KERN_SUCCESS) {
+ kern_error(result, "mach_port_request_notification");
+ reap_server(serverp);
+ dispatch_server(serverp);
+ }
}
break;
}
}
-static void
-unblock_init(task_port_t task, mach_port_t newBootstrap)
-{
- mach_msg_header_t init_go_msg;
- kern_return_t result;
-
- /*
- * Proc 1 is blocked in a msg_receive on its notify port, this lets
- * it continue, and we hand off its new bootstrap port
- */
- init_go_msg.msgh_remote_port = inherited_bootstrap_port;
- init_go_msg.msgh_local_port = newBootstrap;
- init_go_msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND);
- result = mach_msg(&init_go_msg, MACH_SEND_MSG, sizeof(init_go_msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "unblock_init mach_msg(send) failed");
- debug("sent go message");
-}
-
static void
exec_server(server_t *serverp)
{
- int nfds, fd;
- char **argv;
-
+ char **argv;
+ sigset_t mask;
+
/*
* Setup environment for server, someday this should be Mach stuff
* rather than Unix crud
*/
- log("Initiating server %s [pid %d]", serverp->cmd, getpid());
argv = argvize(serverp->cmd);
- nfds = getdtablesize();
-
-#ifdef notyet
- /*
- * If our priority's to be changed, set it up here.
- */
- if (serverp->priority >= 0) {
- kern_return_t result;
- result = task_priority(mach_task_self(), serverp->priority,
- TRUE);
- if (result != KERN_SUCCESS)
- kern_error(result, "task_priority %d",
- serverp->priority);
- }
-#endif /* notyet */
close_errlog();
- /*
- * Mark this process as an "init process" so that it won't be
- * blown away by init when it starts up (or changes states).
- */
- if (init_pid == 1) {
- debug("marking process %s as init_process\n", argv[0]);
- init_process();
+ if (serverp->uid != inherited_uid)
+ if (setuid(serverp->uid) < 0)
+ unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
+ serverp->port, serverp->bootstrap->bootstrap_port,
+ serverp->cmd, serverp->uid);
+
+ if (setsid() < 0) {
+ /*
+ * We can't keep this from happening, but we shouldn't start
+ * the server not as a process group leader. So, just fake like
+ * there was real activity, and exit the child. If needed,
+ * we'll re-launch it under another pid.
+ */
+ serverp->activity = 1;
+ unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
+ serverp->port, serverp->bootstrap->bootstrap_port,
+ serverp->cmd);
}
- for (fd = debugging ? 3 : 0; fd < nfds; fd++)
- close(fd);
- fd = open("/dev/tty", O_RDONLY);
- if (fd >= 0) {
- ioctl(fd, TIOCNOTTY, 0);
- close(fd);
- }
+ sigemptyset(&mask);
+ (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
- execv(argv[0], argv);
- unix_error("Can't exec %s", argv[0]);
+ execv(argv[0], argv);
+ unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
+ serverp->port,
+ serverp->bootstrap->bootstrap_port,
+ serverp->cmd);
}
static char **
return argv;
}
+static void *
+demand_loop(void *arg)
+{
+ mach_msg_empty_rcv_t dummy;
+ kern_return_t dresult;
+
+
+ for(;;) {
+ mach_port_name_array_t members;
+ mach_msg_type_number_t membersCnt;
+ mach_port_status_t status;
+ mach_msg_type_number_t statusCnt;
+ int i;
+
+ /*
+ * Receive indication of message on demand service
+ * ports without actually receiving the message (we'll
+ * let the actual server do that.
+ */
+ dresult = mach_msg(
+ &dummy.header,
+ MACH_RCV_MSG|MACH_RCV_LARGE,
+ 0,
+ 0,
+ demand_port_set,
+ 0,
+ MACH_PORT_NULL);
+ if (dresult != MACH_RCV_TOO_LARGE) {
+ kern_error(dresult, "demand_loop: mach_msg()");
+ continue;
+ }
+
+ /*
+ * If we are shutting down, there is no use processing
+ * any more of these messages.
+ */
+ if (shutdown_in_progress == TRUE)
+ return arg;
+
+ /*
+ * Some port(s) now have messages on them, find out
+ * which ones (there is no indication of which port
+ * triggered in the MACH_RCV_TOO_LARGE indication).
+ */
+ dresult = mach_port_get_set_status(
+ mach_task_self(),
+ demand_port_set,
+ &members,
+ &membersCnt);
+ if (dresult != KERN_SUCCESS) {
+ kern_error(dresult, "demand_loop: mach_port_get_set_status()");
+ continue;
+ }
+
+ for (i = 0; i < membersCnt; i++) {
+ statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
+ dresult = mach_port_get_attributes(
+ mach_task_self(),
+ members[i],
+ MACH_PORT_RECEIVE_STATUS,
+ (mach_port_info_t)&status,
+ &statusCnt);
+ if (dresult != KERN_SUCCESS) {
+ kern_error(dresult, "demand_loop: mach_port_get_attributes()");
+ continue;
+ }
+
+ /*
+ * For each port with messages, take it out of the
+ * demand service portset, and inform the main thread
+ * that it might have to start the server responsible
+ * for it.
+ */
+ if (status.mps_msgcount) {
+ dresult = mach_port_move_member(
+ mach_task_self(),
+ members[i],
+ MACH_PORT_NULL);
+ if (dresult != KERN_SUCCESS) {
+ kern_error(dresult, "demand_loop: mach_port_move_member()");
+ continue;
+ }
+ notify_server_loop(members[i]);
+ }
+ }
+
+ dresult = vm_deallocate(
+ mach_task_self(),
+ (vm_address_t) members,
+ (vm_size_t) membersCnt * sizeof(mach_port_name_t));
+ if (dresult != KERN_SUCCESS) {
+ kern_error(dresult, "demand_loop: vm_deallocate()");
+ continue;
+ }
+ }
+ return NULL;
+}
+
/*
- * server_loop -- pick requests off our service port and process them
+ * server_demux -- processes requests off our service port
* Also handles notifications
*/
-#define bootstrapMaxRequestSize 1024
-#define bootstrapMaxReplySize 1024
-static void
-server_loop(void)
+static boolean_t
+server_demux(
+ mach_msg_header_t *Request,
+ mach_msg_header_t *Reply)
{
bootstrap_info_t *bootstrap;
service_t *servicep;
server_t *serverp;
kern_return_t result;
- mach_port_name_t previous;
- mach_port_array_t array;
- mach_msg_type_number_t count;
- int i;
+ mig_reply_error_t *reply;
- union {
- mach_msg_header_t hdr;
- char body[bootstrapMaxRequestSize];
- } msg;
- union {
- mach_msg_header_t hdr;
-#ifdef notyet
- death_pill_t death;
-#endif /* notyet */
- char body[bootstrapMaxReplySize];
- } reply;
-
- for (;;) {
- memset(&msg, 0, sizeof(msg));
- result = mach_msg_overwrite_trap(&msg.hdr, MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_TIMEOUT, 0, sizeof(msg), bootstrap_port_set, 500, MACH_PORT_NULL, MACH_MSG_NULL, 0);
- if (result != KERN_SUCCESS) {
- if (result != MACH_RCV_TIMED_OUT) {
- kern_error(result, "server_loop: msg_receive()");
- }
- continue;
- }
+ debug("received message on port %x\n", Request->msgh_local_port);
-#if DEBUG
- debug("received message on port %d\n", msg.hdr.msgh_local_port);
-#endif DEBUG
+ /*
+ * Do minimal cleanup and then exit.
+ */
+ if (shutdown_in_progress == TRUE) {
+ log("Shutting down. Deactivating root bootstrap (%x) ...",
+ bootstraps.bootstrap_port);
+ deactivate_bootstrap(&bootstraps);
+ log("Done.");
+ exit(0);
+ }
+
+ reply = (mig_reply_error_t *)Reply;
/*
* Pick off notification messages
*/
- if (msg.hdr.msgh_local_port == notify_port) {
- mach_port_name_t np;
-
- switch (msg.hdr.msgh_id) {
- case MACH_NOTIFY_DEAD_NAME:
- np = ((mach_dead_name_notification_t *)&msg)->not_port;
-#if DEBUG
- info("Notified dead name %d", np);
-#endif DEBUG
- if (np == inherited_bootstrap_port)
- {
- inherited_bootstrap_port = MACH_PORT_NULL;
- forward_ok = FALSE;
- break;
- }
+ if (Request->msgh_local_port == notify_port) {
+ mach_port_name_t np;
+
+ memset(reply, 0, sizeof(*reply));
+ switch (Request->msgh_id) {
+ case MACH_NOTIFY_DEAD_NAME:
+ np = ((mach_dead_name_notification_t *)Request)->not_port;
+ debug("Notified dead name %x", np);
+
+ if (np == inherited_bootstrap_port) {
+ inherited_bootstrap_port = MACH_PORT_NULL;
+ forward_ok = FALSE;
+ }
- /*
- * This may be notification that the task_port associated
- * with a task we've launched has been deleted. This
- * happens only when the server dies.
- */
- serverp = lookup_server_by_task_port(np);
- if (serverp != NULL) {
- info("Notified that server %s died\n", serverp->cmd);
- if (running_servers <= 0) {
- /* This "can't" happen */
- running_servers = 0;
- error("task count error");
- } else {
- running_servers -= 1;
- log("server %s died",
- serverp != NULL ? serverp->cmd : "Unknown");
- if (serverp != NULL) {
- /*
- * FIXME: need to control execs
- * when server fails immediately
- */
- if ( serverp->servertype == RESTARTABLE
- /*
- && haven't started this recently */)
- start_server(serverp);
- }
- }
- break;
- }
+ /*
+ * Check to see if a subset requestor port was deleted.
+ */
+ while (bootstrap = lookup_bootstrap_by_req_port(np)) {
+ debug("Received dead name notification for bootstrap subset %x requestor port %x",
+ bootstrap->bootstrap_port, bootstrap->requestor_port);
+ mach_port_deallocate(
+ mach_task_self(),
+ bootstrap->requestor_port);
+ bootstrap->requestor_port = MACH_PORT_NULL;
+ deactivate_bootstrap(bootstrap);
+ }
- /*
- * Check to see if a subset requestor port was deleted.
- */
- while (bootstrap = lookup_bootstrap_req_by_port(np)) {
- info("notified that requestor of subset %d died",
- bootstrap->bootstrap_port);
- delete_bootstrap(bootstrap);
- }
+ /*
+ * Check to see if a defined service has gone
+ * away.
+ */
+ while (servicep = lookup_service_by_port(np)) {
+ /*
+ * Port gone, registered service died.
+ */
+ debug("Received dead name notification for service %s "
+ "on bootstrap port %x\n",
+ servicep->name, servicep->bootstrap);
+ debug("Service %s failed - deallocate", servicep->name);
+ delete_service(servicep);
+ }
- /*
- * Check to see if a defined service has gone
- * away.
- */
- while (servicep = lookup_service_by_port(np)) {
- /*
- * Port gone, server died.
- */
- debug("Received destroyed notification for service %s "
- "on bootstrap port %d\n",
- servicep->name, servicep->bootstrap);
- if (servicep->servicetype == REGISTERED) {
- debug("Service %s failed - deallocate", servicep->name);
- mach_port_deallocate(mach_task_self(),np);
- mach_port_deallocate(mach_task_self(),servicep->port);
- delete_service(servicep);
- } else {
/*
- * Allocate a new, backed-up port for this service.
+ * Check to see if a launched server task has gone
+ * away.
*/
- log("Service %s failed - re-initialize",
- servicep->name);
- msg_destroy_port(servicep->port);
- result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &servicep->port);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "port_allocate");
- result = mach_port_insert_right(bootstrap_self, servicep->port, servicep->port, MACH_MSG_TYPE_MAKE_SEND);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "mach_port_insert_right");
-#if 0
- result = port_set_backup(mach_task_self(),
- servicep->port,
- backup_port,
- &previous);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "port_set_backup");
-#endif
- servicep->isActive = FALSE;
- }
+ if (serverp = lookup_server_by_task_port(np)) {
+ /*
+ * Port gone, server died.
+ */
+ debug("Received task death notification for server %s ",
+ serverp->cmd);
+ reap_server(serverp);
+ dispatch_server(serverp);
+ }
+
+ mach_port_deallocate(mach_task_self(), np);
+ reply->RetCode = KERN_SUCCESS;
+ break;
+
+ case MACH_NOTIFY_PORT_DELETED:
+ np = ((mach_port_deleted_notification_t *)Request)->not_port;
+ debug("port deleted notification on 0x%x\n", np);
+ reply->RetCode = KERN_SUCCESS;
+ break;
+
+ case MACH_NOTIFY_SEND_ONCE:
+ debug("notification send-once right went unused\n");
+ reply->RetCode = KERN_SUCCESS;
+ break;
+
+ default:
+ error("Unexpected notification: %d", Request->msgh_id);
+ reply->RetCode = KERN_FAILURE;
+ break;
}
- break;
- default:
- error("Unexpected notification: %d", msg.hdr.msgh_id);
- break;
- }
- }
-#if 0
- else if (msg.hdr.msg_local_port == backup_port) {
- notification_t *not = (notification_t *) &msg.hdr;
- mach_port_name_t np = not->notify_port;
-
- /*
- * Port sent back to us, server died.
- */
- info("port %d returned via backup", np);
- servicep = lookup_service_by_port(np);
- if (servicep != NULL) {
- debug("Received %s notification for service %s",
- not->notify_header.msg_id
- == NOTIFY_PORT_DESTROYED
- ? "destroyed" : "receive rights",
- servicep->name);
- log("Service %s failed - port backed-up", servicep->name);
- ASSERT(canReceive(servicep->port));
- servicep->isActive = FALSE;
- result = port_set_backup(mach_task_self(),
- servicep->port,
- backup_port,
- &previous);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "port_set_backup");
- } else
- msg_destroy_port(np);
}
-#endif
- else
- { /* must be a service request */
- bootstrap_server(&msg.hdr, &reply.hdr);
-#ifdef DEBUG
- debug("Handled request.");
-#endif DEBUG
- reply.hdr.msgh_local_port = MACH_PORT_NULL;
- result = mach_msg(&reply.hdr, MACH_SEND_MSG|MACH_SEND_TIMEOUT, reply.hdr.msgh_size, 0, MACH_PORT_NULL,
- BOOTSTRAP_REPLY_TIMEOUT, MACH_PORT_NULL);
-#ifdef DEBUG
- debug("Reply sent.");
-#endif DEBUG
- if (result != MACH_MSG_SUCCESS) {
- kern_error(result, "msg_send");
- }
- }
- /* deallocate uninteresting ports received in message */
- msg_destroy(&msg.hdr);
- }
-}
-/*
- * msg_destroy -- walk through a received message and deallocate any
- * useless ports or out-of-line memory
- */
-static void
-msg_destroy(mach_msg_header_t *m)
-{
-#ifdef notyet /* [ */
- msg_type_t *mtp;
- msg_type_long_t *mtlp;
- void *dp;
- unsigned type, size, num;
- boolean_t inlne;
- mach_port_t *pp;
- kern_return_t result;
+ else if (Request->msgh_local_port == backup_port) {
+ mach_port_name_t np;
+
+ memset(reply, 0, sizeof(*reply));
+
+ np = ((mach_port_destroyed_notification_t *)Request)->not_port.name;
+ servicep = lookup_service_by_port(np);
+ if (servicep != NULL) {
+ server_t *serverp = servicep->server;
+
+ switch (Request->msgh_id) {
+
+ case MACH_NOTIFY_PORT_DESTROYED:
+ /*
+ * Port sent back to us, server died.
+ */
+ debug("Received destroyed notification for service %s",
+ servicep->name);
+ debug("Service %x bootstrap %x backed up: %s",
+ servicep->port, servicep->bootstrap->bootstrap_port,
+ servicep->name);
+ ASSERT(canReceive(servicep->port));
+ servicep->isActive = FALSE;
+ serverp->active_services--;
+ dispatch_server(serverp);
+ reply->RetCode = KERN_SUCCESS;
+ break;
- msg_destroy_port(m->msg_remote_port);
- for ( mtp = (msg_type_t *)(m + 1)
- ; (unsigned)mtp - (unsigned)m < m->msg_size
- ;)
- {
- inlne = mtp->msg_type_inline;
- if (mtp->msg_type_longform) {
- mtlp = (msg_type_long_t *)mtp;
- type = mtlp->msg_type_long_name;
- size = mtlp->msg_type_long_size;
- num = mtlp->msg_type_long_number;
- dp = (void *)(mtlp + 1);
+ case DEMAND_REQUEST:
+ /* message reflected over from demand start thread */
+ if (!active_server(serverp))
+ start_server(serverp);
+ reply->RetCode = KERN_SUCCESS;
+ break;
+
+ default:
+ debug("Mysterious backup_port notification %d", Request->msgh_id);
+ reply->RetCode = KERN_FAILURE;
+ break;
+ }
} else {
- type = mtp->msg_type_name;
- size = mtp->msg_type_size;
- num = mtp->msg_type_number;
- dp = (void *)(mtp + 1);
+ debug("Backup_port notification - previously deleted service");
+ reply->RetCode = KERN_FAILURE;
}
- if (inlne)
- mtp = (msg_type_t *)(dp + num * (size/BITS_PER_BYTE));
- else {
- mtp = (msg_type_t *)(dp + sizeof(void *));
- dp = *(char **)dp;
- }
- if (MSG_TYPE_PORT_ANY(type)) {
- for (pp = (mach_port_t *)dp; num-- > 0; pp++)
- msg_destroy_port(*pp);
- }
- if ( ! inlne ) {
- result = vm_deallocate(mach_task_self(), (vm_address_t)dp,
- num * (size/BITS_PER_BYTE));
- if (result != KERN_SUCCESS)
- kern_error(result,
- "vm_deallocate: msg_destroy");
+ }
+
+ else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
+ mach_port_t ns = Request->msgh_local_port;
+
+ if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) {
+ /*
+ * A server we launched has released his bootstrap
+ * port send right. We won't re-launch him unless
+ * his services came back to roost. But we need to
+ * destroy the bootstrap port for fear of leaking.
+ */
+ debug("server %s dropped server port", serverp->cmd);
+ serverp->port = MACH_PORT_NULL;
+ dispatch_server(serverp);
+ } else if (bootstrap = lookup_bootstrap_by_port(ns)) {
+ /*
+ * The last direct user of a deactivated bootstrap went away.
+ * We can finally free it.
+ */
+ debug("Deallocating bootstrap %x: no more clients", ns);
+ bootstrap->bootstrap_port = MACH_PORT_NULL;
+ deallocate_bootstrap(bootstrap);
}
+
+ result = mach_port_mod_refs(
+ mach_task_self(),
+ ns,
+ MACH_PORT_RIGHT_RECEIVE,
+ -1);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_mod_refs");
+
+ memset(reply, 0, sizeof(*reply));
+ reply->RetCode = KERN_SUCCESS;
+ }
+
+ else { /* must be a service request */
+ debug("Handled request.");
+ return bootstrap_server(Request, Reply);
}
-#endif /* notyet ] */
+ return TRUE;
}
/*
- * msg_destroy_port -- deallocate port if it's not important to bootstrap
- * Bad name, this is used for things other than msg_destroy.
+ * server_loop -- pick requests off our service port and process them
+ * Also handles notifications
*/
-void
-msg_destroy_port(mach_port_t p)
+#define bootstrapMaxRequestSize 1024
+#define bootstrapMaxReplySize 1024
+
+static void
+server_loop(void)
{
- if ( p == MACH_PORT_NULL
- || p == mach_task_self()
- || p == mig_get_reply_port()
- || p == bootstrap_port_set
- || p == inherited_bootstrap_port
- || lookup_service_by_port(p)
- || lookup_server_by_port(p)
- || lookup_bootstrap_by_port(p) != &bootstraps
- || lookup_bootstrap_req_by_port(p) != &bootstraps
- || p == bootstraps.bootstrap_port
- || p == bootstraps.requestor_port)
- return;
-
-#if DEBUG
- debug("Deallocating port %d", p);
-#endif DEBUG
- (void) mach_port_deallocate(mach_task_self(), p);
+ mach_msg_return_t mresult;
+
+ for (;;) {
+ mresult = mach_msg_server(
+ server_demux,
+ bootstrapMaxRequestSize,
+ bootstrap_port_set,
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)|
+ MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
+ if (mresult != MACH_MSG_SUCCESS)
+ kern_error(mresult, "mach_msg_server");
+ }
}
boolean_t
}
return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
}
-void
-set_default_policy(
- mach_port_t master_host_port)
-{
-#if 0
- host_priority_info_data_t host_pri_info;
- mach_port_t default_processor_set_name;
- mach_port_t default_processor_set;
- policy_rr_base_data_t rr_base;
- policy_rr_limit_data_t rr_limit;
- kern_return_t result;
- mach_msg_type_number_t count;
- static char here[] = "default_pager_set_policy";
-
- count = HOST_PRIORITY_INFO_COUNT;
- result = host_info(mach_host_self(),
- HOST_PRIORITY_INFO,
- (host_info_t) &host_pri_info,
- &count);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "Could not get host priority info");
-
- rr_base.quantum = 0;
- rr_base.base_priority = host_pri_info.system_priority;
- rr_limit.max_priority = host_pri_info.system_priority;
-
- (void)processor_set_default(mach_host_self(),
- &default_processor_set_name);
- (void)host_processor_set_priv(master_host_port,
- default_processor_set_name,
- &default_processor_set);
-
- result = task_set_policy(mach_host_self(), default_processor_set,
- POLICY_RR,
- (policy_base_t) & rr_base, POLICY_RR_BASE_COUNT,
- (policy_limit_t) & rr_limit, POLICY_RR_LIMIT_COUNT,
- TRUE);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "Could not set task policy ");
-#endif
-}
* The bootstrap server is the first user-mode task initiated by the Mach
* kernel at system boot time. The bootstrap server provides two services,
* it initiates other system tasks, and manages a table of name-port bindings
- * for fundamental system services (e.g. the NetMsgServer, and the Unix
- * emulation service).
- *
- * The file /etc/bootstrap.conf is read by bootstrap to determine other system
- * services to initiate at system boot time. The format of this file is
- * described later.
+ * for fundamental system services (e.g. lookupd, Window Manager, etc...).
*
* Name-port bindings can be established with the bootstrap server by either
* of two mechanisms:
*
- * 1. The binding can be indicated in the file /etc/bootstrap.conf. In this
- * case, bootstrap will immediately create a port and bind the indicated name
- * with that port. At a later time, a service may "checkin" for the name-port
+ * 1. The binding can be indicated, in advance of the service that backs it
+ * being available, via a "service create" request. In this case, bootstrap
+ * will immediately create a port and bind the indicated name with that port.
+ * At a later time, a service may "checkin" for the name-port
* binding and will be returned receive rights for the bound port. Lookup's
* on bindings created by this mechanism will return send rights to the port,
* even if no service has "checked-in". In this case, requests sent to the
* it is marked available for check-out again. This allows crashed servers to
* resume service to previous clients. Lookup's on this named port will
* continue to be serviced by bootstrap while holding receive rights for the
- * bound port. A client may detect that the service is inactive via the.
- * bootstrap status request. If the service re-registers rather than
- * "checking-in" the original bound port is destroyed.
+ * bound port. A client may detect that the service is inactive via the
+ * bootstrap status request. If an inactive service re-registers rather
+ * than "checking-in" the original bound port is destroyed.
*
* The status of a named service may be obtained via the "status" request.
* A service is "active" if a name-port binding exists and receive rights
* to the bound port are held by a task other than bootstrap.
*
- * Bootstrap initiates server tasks and creates initial name-port bindings as
- * directed by the configuration file /etc/bootstrap.conf. This file has
- * entries with the following formats:
- *
- * services [ SERVICE_NAME ]+ ;
- *
- * E.g:
- * services OldService=1 SomeService;
- *
- * Creates a port and binds the name "OldService" to it.
- * For compatability, assigns the port via mach_ports_register to
- * slot 1. Also creates a port and binds the name "SomeService".
- *
- * self [ SERVICE_NAME ]+ ;
- *
- * E.g:
- * self BootStrapService;
- *
- * Provides a binding to bootstrap's own service port named
- * "BootStrapService".
- *
- * [restartable] server SERVER_FILE_AND_ARGS [ services ... ] ;
- *
- * E.g:
- * server "/usr/etc/sigserver -i" services UnixSignalService;
- *
- * Initiates the server task "/usr/etc/sigserver" with
- * command-line argument "-i", and also creates a name-port
- * binding for the name UnixSignalService. Checkin requests for
- * UnixSignalService are only accepted via the bootstrap service
- * port passed to/usr/etc/sigserver. If the "restartable" option
- * had been specified, bootstrap will reinitiate the server task
- * if it receives notification that all of the server's service
- * ports have been destroyed or deallocated. The server command
- * may be specified without surrounding quotes if it does not
- * include blanks.
- *
- * init SERVER_FILE_AND_ARGS [ services ... ] ;
- *
- * E.g:
- * init /etc/init services NetMsgService=0 PSWindowService=4;
- *
- * Functions like "server" request above, except process is
- * started as pid 1. Illegal if bootstrap itself was not
- * initiated as pid 1.
- *
- * forward;
- *
- * If present, bootstrap will forward unknown lookup requests to
- * its bootstrap service port (if not PORT_NULL), and forward any
- * reply to the original requester.
- *
- * # Comment string up to end of line.
- *
- * A line terminated comment starts with a sharp sign (#).
- *
- * Lexical notes: Strings are either enclosed in double quotes ("), or must
- * start with a letter or underscore (_) and followed by a string of
- * alphanumerics and underscores; backslash (\) escapes the following
- * character. Strings are limited to a (large) length. Numbers must be
- * decimal. Blanks and newlines may be freely used outside of strings.
+ * The bootstrap server may also (re)start server processes associated with
+ * with a set of services. The definition of the server process is done
+ * through the "create server" request. The server will be launched in the
+ * same bootstrap context in which it was registered.
*/
#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
import <servers/bootstrap_defs.h>;
-type name_t = c_string[128];
-type name_array_t = ^array [] of name_t;
-type bool_array_t = ^array [] of boolean_t;
+type cmd_t = c_string[512];
+type name_t = c_string[128];
+type cmd_array_t = ^array [] of cmd_t;
+type name_array_t = ^array [] of name_t;
+type bootstrap_status_t = integer_t;
+type bootstrap_status_array_t = ^array [] of bootstrap_status_t;
serverprefix x_;
-/* old service_checkin */
-skip;
-/* old service_status */
-skip;
+/*
+ * kern_return_t
+ * bootstrap_create_server(mach_port_t bootstrap_port,
+ * cmd_t server_command,
+ * integer_t server_uid,
+ * boolean_t on_demand,
+ * mach_port_t *server_port)
+ *
+ * Declares a server that mach_init will re-spawn within the specified
+ * bootstrap context. The server is considered already "active"
+ * (i.e. will not be re-spawned) until the returned server_port is
+ * deallocated.
+ *
+ * In the meantime, services can be declared against the server,
+ * by using the server_port as the privileged bootstrap target of
+ * subsequent bootstrap_create_service() calls.
+ *
+ * When mach_init re-spawns the server, its task bootstrap port
+ * is set to the privileged sever_port. Through this special
+ * bootstrap port, it can access all of parent bootstrap's context
+ * (and all services are created in the parent's namespace). But
+ * all additional service declarations (and declaration removals)
+ * will be associated with this particular server.
+ *
+ * Only a holder of the server_port privilege bootstrap port can
+ * check in or register over those services.
+ *
+ * When all services associated with a server are deleted, and the server
+ * exits, it will automatically be deleted itself.
+ *
+ * If the server is declared "on_demand," then a non-running server
+ * will be re-launched on first use of one of the service ports
+ * registered against it. Otherwise, it will be re-launched
+ * immediately upon exiting (whether any client is actively using
+ * any of the service ports or not).
+ *
+ * Errors: Returns appropriate kernel errors on rpc failure.
+ * Returns BOOTSTRAP_NOT_PRIVILEGED, bootstrap or uid invalid.
+ */
+routine bootstrap_create_server(
+ bootstrap_port : mach_port_t;
+ server_cmd : cmd_t;
+ server_uid : integer_t;
+ on_demand : boolean_t;
+ ServerSecToken token : security_token_t;
+ out server_port : mach_port_make_send_t);
+
+/*
+ * kern_return_t
+ * bootstrap_unprivileged(mach_port_t bootstrap_port,
+ * mach_port_t *unpriv_port)
+ *
+ * Given a bootstrap port, return its unprivileged equivalent. If
+ * the port is already unprivileged, another reference to the same
+ * port is returned.
+ *
+ * This is most often used by servers, which are launched with their
+ * bootstrap port set to the privileged port for the server, to get
+ * an unprivileged version of the same port for use by its unprivileged
+ * children (or any offspring that it does not want to count as part
+ * of the "server" for mach_init registration and re-launch purposes).
+ */
+routine bootstrap_unprivileged(
+ bootstrap_port : mach_port_t;
+ out unpriv_port : mach_port_t);
/*
* kern_return_t
* bootstrap_check_in(mach_port_t bootstrap_port,
* name_t service_name,
- * port_all_t *service_port)
+ * mach_port_t *service_port)
*
- * Returns all rights to service_port of service named by service_name.
+ * Returns the receive right for the service named by service_name. The
+ * service must have previously been declared in this bootstrap context via
+ * a call to bootstrap_create_service(). Attempts to check_in a service
+ * which is already active are not allowed.
+ *
+ * If the service was declared as being associated with a server, the
+ * check_in must come from the server's privileged port (server_port).
*
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
* name_t service_name,
* mach_port_t service_port)
*
- * Registers send rights for the port service_port for the service named by
- * service_name. Attempts to registering a service where an active binding
- * already exists are rejected. On the otherhand, registering a service where
- * and inactive binding exists (i.e. bootstrap currently holds receive rights
- * for the service port) is allowed; in this case the previous service port
- * will be deallocated. Restarting services wishing to resume service for
- * previous clients must first attempt to checkin to the service in order to
- * recover the previous service port.
+ * Registers a send right for service_port with the service identified by
+ * service_name. Attempts to register a service where an active binding
+ * already exists are rejected.
+ *
+ * If the service was previously declared with bootstrap_create_service(),
+ * but is not currently active, this call can be used to undeclare the
+ * service. The bootstrap port used must have sufficient privilege to
+ * do so. (Registering MACH_PORT_NULL is especially useful for shutting
+ * down declared services).
*
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to
* name_t service_name,
* mach_port_t *service_port)
*
- * Returns send rights for the service port of the service named by
- * service_name in service_port. Service is not guaranteed to be active.
+ * Returns a send right for the service port declared/registered under the
+ * name service_name. The service is not guaranteed to be active. Use the
+ * bootstrap_status call to determine the status of the service.
*
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
out service_ports : mach_port_array_t;
out all_services_known: boolean_t);
-/* old bootstrap_get_unpriv_port */
-skip;
+/*
+ * kern_return_t
+ * bootstrap_parent(mach_port_t bootstrap_port,
+ * mach_port_t *parent_port);
+ *
+ * Given a bootstrap subset port, return the parent bootstrap port.
+ * If the specified bootstrap port is already the root subset,
+ * MACH_PORT_NULL will be returned.
+ *
+ * Errors:
+ * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running
+ * with an effective user id of root (as determined by the security
+ * token in the message trailer).
+ */
+routine bootstrap_parent(
+ bootstrap_port : mach_port_t;
+ ServerSecToken token : security_token_t;
+ out parent_port : mach_port_t);
/*
* kern_return_t
* bootstrap_status(mach_port_t bootstrap_port,
* name_t service_name,
- * boolean_t *service_active);
+ * bootstrap_status_t *service_active);
*
- * Returns: service_active is true if service is available.
+ * Returns: service_active indicates if service is active, inactive, or
+ * associated with a launch-on-demand server.
*
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
routine bootstrap_status(
bootstrap_port : mach_port_t;
service_name : name_t;
- out service_active : boolean_t);
+ out service_active : bootstrap_status_t);
/*
* kern_return_t
bootstrap_port : mach_port_t;
out service_names : name_array_t, dealloc;
out server_names : name_array_t, dealloc;
- out service_active : bool_array_t, dealloc);
+ out service_active : bootstrap_status_array_t, dealloc);
/*
* kern_return_t
* registered with an ancestor port may be registered with the subset port
* are allowed. Services already advertised may then be effectively removed
* by registering PORT_NULL for the service.
- * When it is detected that the requestor_port is destroied the subset
+ * When it is detected that the requestor_port is destroyed the subset
* port and all services advertized by it are destroied as well.
*
* Errors: Returns appropriate kernel errors on rpc failure.
bootstrap_port : mach_port_t;
service_name : name_t;
out service_port : mach_port_t);
+
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#import <mach/mach.h>
#import <mach/boolean.h>
+#import <mach/notify.h>
-#define BASEPRI_USER 10 /* AOF Thu Feb 16 14:42:57 PST 1995 */
+#define BASEPRI_USER 31 /* AOF 20/02/2002 */
#define BITS_PER_BYTE 8 /* this SHOULD be a well defined constant */
#define ANYWHERE TRUE /* For use with vm_allocate() */
+#define DEMAND_REQUEST MACH_NOTIFY_LAST /* demand service messaged */
+
+#define DELAYED_BOOTSTRAP_DESTROY TRUE /* destroyed on last reference */
+
extern const char *program_name;
-extern const char *conf_file;
-extern const char *default_conf;
extern mach_port_t lookup_only_port;
extern mach_port_t inherited_bootstrap_port;
extern mach_port_t self_port; /* Compatability hack */
extern boolean_t forward_ok;
extern boolean_t debugging;
extern mach_port_t bootstrap_port_set;
-extern int init_priority;
+extern mach_port_t demand_port_set;
+extern mach_port_t notify_port;
+extern mach_port_t backup_port;
extern boolean_t canReceive(mach_port_t port);
extern boolean_t canSend(mach_port_t port);
-
-extern void msg_destroy_port(mach_port_t p);
#import "error_log.h"
static pthread_mutex_t errlog_lock = PTHREAD_MUTEX_INITIALIZER;
+static boolean_t stderr_open = FALSE;
+static boolean_t log_stopped = FALSE;
void
-init_errlog(boolean_t is_init)
+init_errlog(boolean_t daemon)
{
int nfds, fd;
- if (is_init) {
- close(0);
- freopen("/dev/console", "r", stdin);
- setbuf(stdin, NULL);
- close(1);
- freopen("/dev/console", "w", stdout);
- setbuf(stdout, NULL);
- close(2);
- freopen("/dev/console", "w", stderr);
- setbuf(stderr, NULL);
+ if (!daemon) {
+ stderr_open = TRUE;
+ nfds = getdtablesize();
+ for (fd = 3; fd < nfds; fd++)
+ close(fd);
+ } else {
+ openlog((char *)program_name, LOG_PID|LOG_CONS, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_DEBUG)); /* we'll do our own filtering */
}
+}
- nfds = getdtablesize();
- for (fd = 3; fd < nfds; fd++)
- close(fd);
- openlog((char *)program_name, LOG_PID, LOG_DAEMON);
- setlogmask(LOG_UPTO(LOG_INFO));
+void
+stop_errlog(void)
+{
+ log_stopped = TRUE;
}
void
close_errlog(void)
{
+ stop_errlog();
closelog();
}
static void do_log(const int level, const char *format, va_list ap)
{
- pthread_mutex_lock(&errlog_lock);
- if (debugging) {
- fprintf(stderr, "%s[%d]%s: ",
- level == LOG_ALERT ? " FATAL" : "",
- getpid(), program_name);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- } else {
- vsyslog(level, format, ap);
+ if (!log_stopped && (debugging || level <= LOG_NOTICE)) {
+ pthread_mutex_lock(&errlog_lock);
+ if (stderr_open) {
+ fprintf(stderr, "%s[%d]%s: ",
+ level == LOG_ALERT ? " FATAL" : "",
+ getpid(), program_name);
+ vfprintf(stderr, format, ap);
+ fprintf(stderr, "\n");
+ } else {
+ vsyslog(level, format, ap);
+ }
+ pthread_mutex_unlock(&errlog_lock);
}
- pthread_mutex_unlock(&errlog_lock);
}
void debug(const char *format, ...)
#import <mach/mach.h>
-extern void init_errlog(boolean_t is_init);
+extern void init_errlog(boolean_t);
+extern void stop_errlog(void);
+extern void close_errlog(void);
extern void debug(const char *format, ...);
extern void info(const char *format, ...);
extern void log(const char *format, ...);
extern void fatal(const char *msg, ...);
extern void kern_fatal(kern_return_t result, const char *msg, ...);
extern void unix_fatal(const char *msg, ...);
-extern void close_errlog(void);
+++ /dev/null
-services FreeService1 FreeService2 EnvironService=1;
-init testServer services Service=2 TerminalService;
-# server "/NextApps/Terminal -Lines 24 -Columns 60" services TerminalService;
-server "/NextApps/Shell" services ShellService;
-machports 0=NetMsgService=0 3=WindowService=3;
-
-
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
void
init_lists(void)
{
+ bootstraps.ref_count = 2; /* make sure we never deallocate this one */
bootstraps.next = bootstraps.prev = &bootstraps;
servers.next = servers.prev = &servers;
services.next = services.prev = &services;
server_t *
new_server(
- servertype_t servertype,
- const char *cmd,
- int priority)
+ bootstrap_info_t *bootstrap,
+ const char *cmd,
+ int uid,
+ servertype_t servertype)
{
server_t *serverp;
- debug("adding new server \"%s\" with priority %d\n", cmd, priority);
+ debug("adding new server \"%s\" with uid %d\n", cmd, uid);
serverp = NEW(server_t, 1);
if (serverp != NULL) {
/* Doubly linked list */
serverp->next = &servers;
servers.prev = serverp;
+ bootstrap->ref_count++;
+ serverp->bootstrap = bootstrap;
+
+ serverp->pid = NO_PID;
+ serverp->task_port = MACH_PORT_NULL;
+ serverp->uid = uid;
+
serverp->port = MACH_PORT_NULL;
serverp->servertype = servertype;
- serverp->priority = priority;
+ serverp->activity = 0;
+ serverp->active_services = 0;
strncpy(serverp->cmd, cmd, sizeof serverp->cmd);
LAST_ELEMENT(serverp->cmd) = '\0';
}
return serverp;
}
-
+
service_t *
new_service(
bootstrap_info_t *bootstrap,
servicetype_t servicetype,
server_t *serverp)
{
- extern mach_port_t notify_port;
service_t *servicep;
- mach_port_t pport;
- kern_return_t result;
servicep = NEW(service_t, 1);
if (servicep != NULL) {
strncpy(servicep->name, name, sizeof servicep->name);
LAST_ELEMENT(servicep->name) = '\0';
+ servicep->servicetype = servicetype;
servicep->bootstrap = bootstrap;
- servicep->server = serverp;
servicep->port = service_port;
- result = mach_port_request_notification(mach_task_self(),
- service_port,
- MACH_NOTIFY_DEAD_NAME,
- 0,
- notify_port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &pport);
- if (result == KERN_SUCCESS) {
- debug("added notification for %s\n", servicep->name);
- } else {
- error("couldn't add notification for %s: %s\n", servicep->name, mach_error_string(result));
- }
- servicep->isActive = isActive;
- servicep->servicetype = servicetype;
+ servicep->server = serverp;
+ servicep->isActive = isActive;
}
return servicep;
}
mach_port_t bootstrap_port,
mach_port_t requestor_port)
{
- extern mach_port_t notify_port;
bootstrap_info_t *bootstrap;
- mach_port_t pport;
- kern_return_t result;
bootstrap = NEW(bootstrap_info_t, 1);
if (bootstrap != NULL) {
bootstrap->bootstrap_port = bootstrap_port;
bootstrap->requestor_port = requestor_port;
- bootstrap->parent = parent;
- result = mach_port_request_notification(mach_task_self(),
- requestor_port,
- MACH_NOTIFY_DEAD_NAME,
- 0,
- notify_port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &pport);
- if (result == KERN_SUCCESS) {
- info("added notification for sub-bootstrap");
- } else {
- error("couldn't add notification for sub-bootstrap: %s\n", mach_error_string(result));
- }
+ bootstrap->ref_count = 1;
+ bootstrap->parent = parent;
+ parent->ref_count++;
}
return bootstrap;
}
lookup_bootstrap_by_port(mach_port_t port)
{
bootstrap_info_t *bootstrap;
+ bootstrap_info_t *first;
+ server_t *serverp;
- for ( bootstrap = FIRST(bootstraps)
- ; !IS_END(bootstrap, bootstraps)
- ; bootstrap = NEXT(bootstrap))
- {
+ bootstrap = first = FIRST(bootstraps);
+ do {
if (bootstrap->bootstrap_port == port)
return bootstrap;
+ bootstrap = NEXT(bootstrap);
+ } while (bootstrap != first);
+
+ for ( serverp = FIRST(servers)
+ ; !IS_END(serverp, servers)
+ ; serverp = NEXT(serverp))
+ {
+ if (port == serverp->port)
+ return serverp->bootstrap;
}
-
- return &bootstraps;
+ return NULL;
}
bootstrap_info_t *
-lookup_bootstrap_req_by_port(mach_port_t port)
+lookup_bootstrap_by_req_port(mach_port_t port)
{
bootstrap_info_t *bootstrap;
delete_service(service_t *servicep)
{
unlink_service(servicep);
+ switch (servicep->servicetype) {
+ case REGISTERED:
+ info("Registered service %s deleted", servicep->name);
+ mach_port_deallocate(mach_task_self(), servicep->port);
+ break;
+ case DECLARED:
+ info("Declared service %s now unavailable", servicep->name);
+ mach_port_deallocate(mach_task_self(), servicep->port);
+ mach_port_mod_refs(mach_task_self(), servicep->port,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ break;
+ case SELF:
+ error("Self service %s now unavailable", servicep->name);
+ break;
+ default:
+ error("unknown service type %d\n", servicep->servicetype);
+ break;
+ }
free(servicep);
nservices -= 1;
}
void
-destroy_services(bootstrap_info_t *bootstrap)
+delete_bootstrap_services(bootstrap_info_t *bootstrap)
{
+ server_t *serverp;
service_t *servicep;
service_t *next;
next = NEXT(servicep);
if (bootstrap != servicep->bootstrap)
continue;
- unlink_service(servicep);
- switch (servicep->servicetype) {
- case REGISTERED:
- log("Service %s deleted - bootstrap deleted", servicep->name);
- msg_destroy_port(servicep->port);
- delete_service(servicep);
- break;
- case DECLARED: // don't alter status of (now unavailable) server
- error("Declared service %s now unavailable", servicep->name);
+
+ if (!servicep->isActive || !servicep->server) {
delete_service(servicep);
- break;
- case SELF:
- error("Self service %s now unavailable", servicep->name);
- break;
- default:
- error("unknown service type %d\n", servicep->servicetype);
- break;
+ continue;
}
+
+ serverp = servicep->server;
+ delete_service(servicep);
+ serverp->active_services--;
+ if (!active_server(serverp))
+ delete_server(serverp);
}
}
return NULL;
}
+service_t *
+lookup_service_by_server(server_t *serverp)
+{
+ service_t *servicep;
+
+ for ( servicep = FIRST(services)
+ ; !IS_END(servicep, services)
+ ; servicep = NEXT(servicep))
+ {
+ if (serverp == servicep->server)
+ return servicep;
+ }
+ return NULL;
+}
+
server_t *
lookup_server_by_task_port(mach_port_t port)
{
return NULL;
}
-void
-delete_bootstrap(bootstrap_info_t *bootstrap)
-{
- bootstrap_info_t *child_bootstrap;
-
- ASSERT(bootstrap->prev->next == bootstrap);
- ASSERT(bootstrap->next->prev == bootstrap);
-
- destroy_services(bootstrap);
- for ( child_bootstrap = FIRST(bootstraps)
- ; !IS_END(child_bootstrap, bootstraps)
- ; child_bootstrap = NEXT(child_bootstrap))
- {
- if (child_bootstrap->parent == bootstrap)
- delete_bootstrap(child_bootstrap);
- }
-
- debug("deleting bootstrap %d, requestor %d",
- bootstrap->bootstrap_port,
- bootstrap->requestor_port);
- bootstrap->prev->next = bootstrap->next;
- bootstrap->next->prev = bootstrap->prev;
- mach_port_destroy(mach_task_self(), bootstrap->bootstrap_port);
- mach_port_deallocate(mach_task_self(), bootstrap->requestor_port);
- free(bootstrap);
-}
-
server_t *
lookup_server_by_port(mach_port_t port)
{
return NULL;
}
-server_t *
-find_init_server(void)
+void
+delete_server(server_t *serverp)
{
- server_t *serverp;
-
- for ( serverp = FIRST(servers)
- ; !IS_END(serverp, servers)
- ; serverp = NEXT(serverp))
+ service_t *servicep;
+ service_t *next;
+
+ info("Deleting server %s", serverp->cmd);
+ ASSERT(serverp->prev->next == serverp);
+ ASSERT(serverp->next->prev == serverp);
+ serverp->prev->next = serverp->next;
+ serverp->next->prev = serverp->prev;
+
+ for ( servicep = FIRST(services)
+ ; !IS_END(servicep, services)
+ ; servicep = next)
{
- if (serverp->servertype == ETCINIT)
- return serverp;
+ next = NEXT(servicep);
+ if (serverp == servicep->server)
+ delete_service(servicep);
}
- return NULL;
+
+ deallocate_bootstrap(serverp->bootstrap);
+
+#ifndef DELAYED_BOOTSTRAP_DESTROY
+ if (serverp->port)
+ mach_port_mod_refs(mach_task_self(), serverp->port,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+#endif
+
+ free(serverp);
+}
+
+void
+deactivate_bootstrap(bootstrap_info_t *bootstrap)
+{
+ bootstrap_info_t *deactivating_bootstraps;
+ bootstrap_info_t *query_bootstrap;
+ bootstrap_info_t *next_limit;
+ bootstrap_info_t *limit;
+
+ /*
+ * we need to recursively deactivate the whole subset tree below
+ * this point. But we don't want to do real recursion because
+ * we don't have a limit on the depth. So, build up a chain of
+ * active bootstraps anywhere underneath this one.
+ */
+ deactivating_bootstraps = bootstrap;
+ bootstrap->deactivate = NULL;
+ for (next_limit = deactivating_bootstraps, limit = NULL
+ ; deactivating_bootstraps != limit
+ ; limit = next_limit, next_limit = deactivating_bootstraps)
+ {
+ for (bootstrap = deactivating_bootstraps
+ ; bootstrap != limit
+ ; bootstrap = bootstrap->deactivate)
+ {
+ for ( query_bootstrap = FIRST(bootstraps)
+ ; !IS_END(query_bootstrap, bootstraps)
+ ; query_bootstrap = NEXT(query_bootstrap))
+ {
+ if (query_bootstrap->parent == bootstrap &&
+ query_bootstrap->requestor_port != MACH_PORT_NULL) {
+ mach_port_deallocate(
+ mach_task_self(),
+ query_bootstrap->requestor_port);
+ query_bootstrap->requestor_port = MACH_PORT_NULL;
+ query_bootstrap->deactivate = deactivating_bootstraps;
+ deactivating_bootstraps = query_bootstrap;
+ }
+ }
+ }
+ }
+
+ /*
+ * The list is ordered with the furthest away progeny being
+ * at the front, and concluding with the one we started with.
+ * This allows us to safely deactivate and remove the reference
+ * each holds on their parent without fear of the chain getting
+ * corrupted (because each active parent holds a reference on
+ * itself and that doesn't get removed until we reach its spot
+ * in the list).
+ */
+ do {
+ bootstrap = deactivating_bootstraps;
+ deactivating_bootstraps = bootstrap->deactivate;
+
+ info("deactivating bootstrap %x", bootstrap->bootstrap_port);
+
+ delete_bootstrap_services(bootstrap);
+
+ mach_port_deallocate(mach_task_self(), bootstrap->bootstrap_port);
+
+#ifdef DELAYED_BOOTSTRAP_DESTROY
+ {
+ mach_port_t previous;
+ mach_port_request_notification(
+ mach_task_self(),
+ bootstrap->bootstrap_port,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ bootstrap->bootstrap_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ }
+#else
+ mach_port_mod_refs(
+ mach_task_self(),
+ bootstrap->bootstrap_port,
+ MACH_PORT_RIGHT_RECEIVE,
+ -1);
+ bootstrap->bootstrap_port = MACH_PORT_NULL;
+ deallocate_bootstrap(bootstrap);
+#endif
+
+ } while (deactivating_bootstraps != NULL);
+}
+
+void
+deallocate_bootstrap(bootstrap_info_t *bootstrap)
+{
+ ASSERT(bootstrap->prev->next == bootstrap);
+ ASSERT(bootstrap->next->prev == bootstrap);
+ if (--bootstrap->ref_count > 0)
+ return;
+
+ bootstrap->prev->next = bootstrap->next;
+ bootstrap->next->prev = bootstrap->prev;
+ deallocate_bootstrap(bootstrap->parent);
+ free(bootstrap);
}
void *
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* lists.h -- interface to list routines
*/
+#import <sys/types.h>
#import <mach/mach.h>
#import <mach/boolean.h>
#import <servers/bootstrap_defs.h>
bootstrap_info_t *next; /* list of all bootstraps */
bootstrap_info_t *prev;
bootstrap_info_t *parent;
+ bootstrap_info_t *deactivate; /* list being deactivated */
mach_port_name_t bootstrap_port;
mach_port_name_t requestor_port;
+ unsigned int ref_count;
};
/* Service types */
typedef enum {
SERVER, /* Launchable server */
RESTARTABLE, /* Restartable server */
- ETCINIT, /* Special processing for /etc/init */
- MACHINIT /* mach_init doesn't get launched. */
+ DEMAND, /* Restartable server - on demand */
+ MACHINIT, /* mach_init doesn't get launched. */
} servertype_t;
#define NULL_SERVER NULL
server_t *prev;
servertype_t servertype;
cmd_t cmd; /* server command to exec */
- int priority; /* priority to give server */
+ int uid; /* uid to exec server with */
mach_port_t port; /* server's priv bootstrap port */
- mach_port_name_t task_port; /* server's task port */
+ mach_port_t task_port; /* server's task port */
+ pid_t pid; /* server's pid */
+ int activity; /* count of checkins/registers this instance */
+ int active_services;/* count of active services */
+ bootstrap_info_t *bootstrap; /* bootstrap context */
};
#define NO_PID (-1)
extern void init_lists(void);
+
extern server_t *new_server(
- servertype_t servertype,
- const char *cmd,
- int priority);
-extern service_t *new_service(
+ bootstrap_info_t *bootstrap,
+ const char *cmd,
+ int uid,
+ servertype_t servertype);
+
+extern service_t *new_service(
bootstrap_info_t *bootstrap,
- const char *name,
- mach_port_t service_port,
- boolean_t isActive,
- servicetype_t servicetype,
- server_t *serverp);
+ const char *name,
+ mach_port_t service_port,
+ boolean_t isActive,
+ servicetype_t servicetype,
+ server_t *serverp);
+
extern bootstrap_info_t *new_bootstrap(
bootstrap_info_t *parent,
mach_port_name_t bootstrap_port,
extern server_t *lookup_server_by_port(mach_port_t port);
extern server_t *lookup_server_by_task_port(mach_port_t port);
-extern bootstrap_info_t *lookup_bootstrap_by_port(mach_port_t port);
-extern bootstrap_info_t *lookup_bootstrap_req_by_port(mach_port_t port);
+extern void setup_server(server_t *serverp);
+extern void delete_server(server_t *serverp);
+extern boolean_t active_server(server_t *serverp);
+extern boolean_t useless_server(server_t *serverp);
+
+extern void delete_service(service_t *servicep);
extern service_t *lookup_service_by_name(bootstrap_info_t *bootstrap, name_t name);
extern service_t *lookup_service_by_port(mach_port_t port);
-extern server_t *find_init_server(void);
-extern void delete_service(service_t *servicep);
-extern void delete_bootstrap(bootstrap_info_t *bootstrap);
+extern service_t *lookup_service_by_server(server_t *serverp);
+
+extern bootstrap_info_t *lookup_bootstrap_by_port(mach_port_t port);
+extern bootstrap_info_t *lookup_bootstrap_by_req_port(mach_port_t port);
+extern void deactivate_bootstrap(bootstrap_info_t *bootstrap);
+extern void deallocate_bootstrap(bootstrap_info_t *bootstrap);
+extern boolean_t active_bootstrap(bootstrap_info_t *bootstrap);
+
extern void *ckmalloc(unsigned nbytes);
extern bootstrap_info_t bootstraps; /* head of list of bootstrap ports */
--- /dev/null
+.\" Copyright (c) 2002, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd March 20, 2002
+.Dt MACH_INIT 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm mach_init
+.Nd Mach service naming (bootstrap) daemon
+.Sh SYNOPSIS
+.Nm mach_init
+.Op Fl D
+.Op Fl d
+.Op Fl F
+.Op Fl r Ar name-in-existing-server
+.Sh DESCRIPTION
+.Nm mach_init
+is a daemon that maintains various mappings between service names and
+the Mach ports that provide access to those services. Clients of mach_init
+can register and lookup services, create new mapping subsets, and
+associate services with declared servers. The mach_init daemon will
+also be responsible for launching (and/or re-launching) those service
+providing servers when attempts to use one or more of the associated services
+is detected.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl D
+When the
+.Fl D
+option is specified,
+.Nm mach_init
+starts in normal (non-debug) mode. This is the default.
+.It Fl d
+When the
+.Fl d
+option is specified,
+.Nm mach_init
+starts in debug mode.
+.It Fl F
+When the
+.Fl F
+option is specified,
+.Nm mach_init
+forks during initialization so that it doesn't have to be put in
+the background manually by the caller.
+.It Fl r
+Using the
+.Fl r
+option tells
+.Nm mach_init
+to register itself in a previously running copy of
+.Nm mach_init
+under the service name
+.Ar name-in-existing-server.
+This is most useful when debugging new instances of
+.Nm mach_init
+itself, but can also be used for robustness or to allow the subsequent
+.Nm mach_init
+processes to run as a non-root user. As mach_init is often used to
+launch servers, this could be more secure. However,
+.Nm mach_init
+will not allow a server declaration to specify a user id different
+than that of the requesting client (unless the client is running as root).
+So it shouldn't be required for a secure configuration.
+.El
+.Pp
+Access to
+.Nm mach_init
+is provided through the bootstrap series of RPC APIs
+over service ports published by mach_init itself. Each Mach task has
+an assigned bootstrap port retrieved via task_get_bootstrap_port().
+These bootstrap port registrations are inherited across fork().
+.Pp
+The service registrations are grouped into subsets, providing a level
+of security. Only processes with access to the subset's bootstrap port
+will be able to register/lookup Mach ports within that subset. Lookups
+from within a subset will search the subset first, then move on to its
+parent, and then its grand-parent, etc... until a string name match is
+found or the top of the bootstrap tree is reached. Subsets are sometimes
+associated with login sessions to protect session-specific ports from being
+exposed outside the session.
+.Pp
+The first instance of
+.Nm mach_init
+is responsible for launching the traditional BSD process control initialization
+daemon (/sbin/init).
+.Sh SAMPLE USAGE
+.Pp
+mach_init -d -r com.company.bootstrap
+.Pp
+.Nm mach_init
+will start in debug mode, and register itself in an already running
+instance of
+.Nm mach_init
+under the service name com.company.bootstrap.
+.Sh NOTE
+.Pp
+Sending a SIGHUP to a running mach_init will toggle debug mode.
+.Sh SEE ALSO
+.Xr init 8
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * bootstrap -- fundamental service initiator and port server
- * Mike DeMoney, NeXT, Inc.
- * Copyright, 1990. All rights reserved.
- *
- * parser.c -- configuration file parser
- */
-#import <mach/boolean.h>
-#import <mach/port.h>
-
-#import <string.h>
-#import <libc.h>
-#import <ctype.h>
-#import <stdio.h>
-
-#import "lists.h"
-#import "bootstrap_internal.h"
-#import "error_log.h"
-#import "parser.h"
-
-
-#ifndef ASSERT
-#define ASSERT(p)
-#endif
-
-#define MAX_TOKEN_LEN 128
-
-#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
-#define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
-#define STREQ(a, b) (strcmp(a, b) == 0)
-#define NEW(type, num) ((type *)ckmalloc(sizeof(type) * (num)))
-
-typedef enum {
- ASSIGN_TKN, EOF_TKN, FORWARD_TKN, INIT_TKN, NUM_TKN,
- RESTARTABLE_TKN, SELF_TKN, SEMICOLON_TKN, SERVER_TKN, SERVICES_TKN,
- STRING_TKN, ERROR_TKN, PRI_TKN
-} token_t;
-
-typedef struct {
- char *string;
- token_t token;
-} keyword_t;
-
-static keyword_t keywords[] = {
- { "forward", FORWARD_TKN },
- { "init", INIT_TKN },
- { "priority", PRI_TKN },
- { "restartable", RESTARTABLE_TKN },
- { "self", SELF_TKN },
- { "server", SERVER_TKN },
- { "services", SERVICES_TKN },
- { NULL, ERROR_TKN }
-};
-
-static FILE *conf;
-static int (*charget)(void);
-static const char *default_conf_ptr;
-
-static char token_string[MAX_TOKEN_LEN];
-static token_t current_token;
-static int token_num;
-static int token_priority;
-static int peekc;
-
-static int get_from_conf(void);
-static int get_from_default(void);
-static boolean_t parse_conf_file(void);
-static boolean_t parse_self(void);
-static boolean_t parse_server(void);
-static boolean_t parse_service(server_t *serverp);
-static boolean_t parse_pri(void);
-static void advance_token(void);
-static token_t keyword_lookup(void);
-
-/*
- * init_config -- read configuration file and build-up initial server and
- * service lists
- *
- * If can't find a suitable bootstrap.conf, use configuration given in
- * bootstrap.c to get system booted so someone can correct bootstrap.conf
- */
-void
-init_config(void)
-{
- boolean_t parse_ok;
-
- conf = fopen(conf_file, "r");
- if (conf != NULL)
- charget = get_from_conf;
- else {
- error("Can't open %s -- using default configuration", conf_file);
- charget = get_from_default;
- }
-
- parse_ok = parse_conf_file();
- if ( ! parse_ok && charget == get_from_conf) {
- error("Can't parse %s -- using default configuration", conf_file);
- charget = get_from_default;
- init_lists();
- peekc = 0;
- parse_ok = parse_conf_file();
- }
- if ( ! parse_ok )
- fatal("Can't parse default configuration file");
-}
-
-/*
- * Function pointer "charget" points at get_from_conf or get_from_default
- */
-static int
-get_from_conf(void)
-{
- return getc(conf);
-}
-
-static int
-get_from_default(void)
-{
- int c;
-
- if (default_conf_ptr == NULL)
- default_conf_ptr = default_conf;
-
- if (c = *default_conf_ptr)
- default_conf_ptr++;
- if (c == '\0')
- c = EOF;
- return c;
-}
-
-/*
- * What follows is a simple recursive descent parser
- * ("we don't need no stinkin' yacc")
- */
-static boolean_t
-parse_conf_file(void)
-{
- boolean_t parse_ok, good_parse;
-
- /*
- * Configuration file syntax (and parsing routines).
- *
- * (parse_conf_file)
- * CONF_FILE := STMT [ ; STMT ]* [ ; ]
- * STMT := SERVER | SERVICE | SELF | forward | initpri
- *
- * (parse_server)
- * SERVER := [ restartable ] ( server | init ) SERVER_PATH_ARGS [ SERVICE ]
- *
- * (parse_service)
- * SERVICE := services [ SERVICE_DECL ]+
- * SERVICE_DECL := SERVICE_NAME
- *
- * (parse_self)
- * SELF := self [ priority = NUM ] SERVICE_DECL
- *
- * Or more simply, just a list of:
- *
- * [[restartable] (server|init) SERVER_PATH_ARGS] [ priority = NUM ]
- * [services SERVICE_NAME [ SERVICE_NAME [ = NUM ]]*] ;
- *
- * self [ SERVICE_NAME ]+
- *
- * [ forward ]
- *
- */
- advance_token();
- if (current_token == EOF_TKN) {
- error("Empty configuration file: %s", conf_file);
- return FALSE;
- }
-
- good_parse = TRUE;
- while (current_token != EOF_TKN) {
- parse_ok = TRUE;
- switch (current_token) {
- case RESTARTABLE_TKN:
- case SERVER_TKN:
- case INIT_TKN:
- parse_ok = parse_server();
- break;
- case SERVICES_TKN:
- parse_ok = parse_service(NULL);
- break;
- case SELF_TKN:
- parse_ok = parse_self();
- break;
- case FORWARD_TKN:
- forward_ok = TRUE;
- advance_token();
- break;
- case SEMICOLON_TKN:
- advance_token();
- break;
- case EOF_TKN:
- break;
- default:
- parse_error(token_string, "start of new declaration");
- parse_ok = FALSE;
- break;
- }
- switch (current_token) {
- case SEMICOLON_TKN:
- advance_token();
- break;
- case EOF_TKN:
- break;
- default:
- if (parse_ok)
- parse_error(token_string, "expected ';'");
- /* Try to re-sync with input */
- while (current_token != SEMICOLON_TKN && current_token != EOF_TKN)
- advance_token();
- parse_ok = FALSE;
- break;
- }
- if (! parse_ok)
- good_parse = FALSE;
- }
- return good_parse;
-}
-
-static boolean_t
-parse_self(void)
-{
- name_t name;
-
- ASSERT(current_token == SELF_TKN);
- advance_token(); /* Skip SELF_TKN */
- if (current_token == PRI_TKN) {
- boolean_t ok;
- ok = parse_pri();
- if (!ok)
- return FALSE;
- init_priority = token_priority;
- }
- while (current_token == STRING_TKN) {
- if (strlen(token_string) >= sizeof(name_t)) {
- parse_error(token_string, "Service name too long");
- return FALSE;
- }
- if (lookup_service_by_name(&bootstraps, token_string) != NULL)
- {
- parse_error(token_string, "Service name previously declared");
- return FALSE;
- }
- strcpy(name, token_string);
- advance_token();
- (void) new_service(&bootstraps, name, MACH_PORT_NULL, ACTIVE, SELF,
- NULL_SERVER);
- }
- return TRUE;
-}
-
-static boolean_t
-parse_server(void)
-{
- server_t *serverp;
- servertype_t servertype = SERVER;
-
- if (current_token == RESTARTABLE_TKN) {
- advance_token();
- servertype = RESTARTABLE;
- }
- switch (current_token) {
- case SERVER_TKN:
- advance_token();
- break;
- case INIT_TKN:
- if (find_init_server() != NULL) {
- parse_error(token_string,
- "Can't specify multiple init servers");
- return FALSE;
- }
- if (servertype == RESTARTABLE) {
- parse_error(token_string,
- "Init server can not be restartable");
- return FALSE;
- }
- servertype = ETCINIT;
- advance_token();
- break;
- default:
- parse_error(token_string, "expected \"server\" or \"init\"");
- return FALSE;
- }
- if (current_token == PRI_TKN) {
- boolean_t ok;
- ok = parse_pri();
- if (!ok)
- return FALSE;
- } else
- token_priority = BASEPRI_USER;
- if (current_token != STRING_TKN) {
- parse_error(token_string,
- "expected string giving server to exec");
- return FALSE;
- }
- serverp = new_server(servertype, token_string, token_priority);
- advance_token();
- if (current_token == SERVICES_TKN)
- return parse_service(serverp);
- return TRUE;
-}
-
-static boolean_t
-parse_service(server_t *serverp)
-{
- name_t name;
-
- ASSERT(current_token == SERVICES_TKN);
- advance_token(); /* Skip SERVICES_TKN */
- while (current_token == STRING_TKN) {
- if (strlen(token_string) >= sizeof(name_t)) {
- parse_error(token_string, "Service name too long");
- return FALSE;
- }
- if (lookup_service_by_name(&bootstraps, token_string) != NULL)
- {
- parse_error(token_string, "Service name previously declared");
- return FALSE;
- }
- strcpy(name, token_string);
- advance_token();
- (void) new_service(&bootstraps, name, MACH_PORT_NULL, !ACTIVE,
- DECLARED, serverp);
- }
- return TRUE;
-}
-
-/*
- * Parse priority=NUM
- */
-static boolean_t
-parse_pri(void)
-{
- ASSERT(current_token == PRI_TKN);
- advance_token(); /* Skip PRI_TKN */
- if (current_token != ASSIGN_TKN) {
- parse_error(token_string, "expected '='");
- return FALSE;
- }
- advance_token(); /* Skip = */
- if (current_token != NUM_TKN) {
- parse_error(token_string, "expected NUM");
- return FALSE;
- }
- advance_token(); /* Skip NUM */
- token_priority = token_num;
- return TRUE;
-}
-/*
- * advance_token -- advances input to next token
- * Anything from a '#' on is comment and ignored
- *
- * On return:
- * current_token contains token_t of next token
- * token_string contains string value of next token
- * if token was number, token_num contains numeric value of token
- */
-static void
-advance_token(void)
-{
- char *cp;
-
-again:
- while (peekc == '\0' || isspace(peekc))
- peekc = (*charget)();
-
- /* Skip comments */
- if (peekc == '#') {
- while (peekc != EOF && peekc != '\n')
- peekc = (*charget)();
- goto again;
- }
-
- cp = token_string;
- *cp = '\0';
-
- if (peekc == EOF) {
- current_token = EOF_TKN;
- return;
- }
-
- if (isalpha(peekc) || peekc == '\\') {
- /*
- * this only allows names to be alphanumerics, '_', and
- * backslash escaped characters.
- * If you want something fancier, use "..."
- */
- current_token = STRING_TKN; /* guarantee it's not ERROR_TKN */
- for (; isalnum(peekc) || peekc == '_' || peekc == '\\';
- peekc = (*charget)()) {
- if (cp >= &LAST_ELEMENT(token_string)) {
- cp = token_string;
- parse_error(token_string, "token too long");
- current_token = ERROR_TKN;
- }
- if (peekc == '\\')
- peekc = (*charget)();
- *cp++ = peekc;
- }
- *cp = '\0';
- if (current_token != ERROR_TKN)
- current_token = keyword_lookup();
- return;
- }
-
- /* Handle "-quoted strings */
- if (peekc == '"') {
- peekc = (*charget)();
- for (; peekc != EOF && peekc != '"'; peekc = (*charget)()) {
- if (cp >= &LAST_ELEMENT(token_string)) {
- cp = token_string;
- parse_error(token_string, "token too long");
- current_token = ERROR_TKN;
- }
- if (peekc == '\\')
- peekc = (*charget)();
- if (peekc == '\n') {
- cp = token_string;
- parse_error(token_string, "Missing \"");
- current_token = ERROR_TKN;
- }
- *cp++ = peekc;
- }
- if (peekc == EOF) {
- cp = token_string;
- parse_error(token_string, "Missing \"");
- current_token = ERROR_TKN;
- } else
- peekc = (*charget)(); /* skip closing " */
- *cp = '\0';
- if (current_token != ERROR_TKN)
- current_token = STRING_TKN;
- return;
- }
-
- if (isdigit(peekc)) {
- for (token_num = 0; isdigit(peekc); peekc = (*charget)())
- token_num = token_num * 10 + peekc - '0';
- current_token = NUM_TKN;
- return;
- }
-
- if (peekc == ';') {
- peekc = (*charget)();
- current_token = SEMICOLON_TKN;
- return;
- }
-
- if (peekc == '=') {
- peekc = (*charget)();
- current_token = ASSIGN_TKN;
- return;
- }
-
- current_token = ERROR_TKN;
- return;
-}
-
-static token_t
-keyword_lookup(void)
-{
- keyword_t *kwp;
-
- for (kwp = keywords; kwp->string; kwp++)
- if (STREQ(kwp->string, token_string))
- return kwp->token;
- return STRING_TKN;
-}
-
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * bootstrap -- fundamental service initiator and port server
- * Mike DeMoney, NeXT, Inc.
- * Copyright, 1990. All rights reserved.
- *
- * parser.h -- interface to configuration file parser
- */
-#import "lists.h"
-
-extern void init_config(void);
-
-
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#define NULL ((void *)0)
#endif NULL
+#define bsstatus(servicep) \
+ (((servicep)->isActive) ? BOOTSTRAP_STATUS_ACTIVE : \
+ (((servicep)->server && (servicep)->server->servertype == DEMAND) ? \
+ BOOTSTRAP_STATUS_ON_DEMAND : BOOTSTRAP_STATUS_INACTIVE))
+
/* extern port_all_t backup_port; */
+/*
+ * kern_return_t
+ * bootstrap_create_server(mach_port_t bootstrap_port,
+ * cmd_t server_cmd,
+ * integer_t server_uid,
+ * boolean_t on_demand,
+ * mach_port_t *server_portp)
+ *
+ * Returns send rights to server_port of service. At this point, the
+ * server appears active, so nothing will try to launch it. The server_port
+ * can be used to delare services associated with this server by calling
+ * bootstrap_create_service() and passing server_port as the bootstrap port.
+ *
+ * Errors: Returns appropriate kernel errors on rpc failure.
+ * Returns BOOTSTRAP_NOT_PRIVILEGED, if bootstrap port invalid.
+ */
+kern_return_t
+x_bootstrap_create_server(
+ mach_port_t bootstrap_port,
+ cmd_t server_cmd,
+ int server_uid,
+ boolean_t on_demand,
+ security_token_t sectoken,
+ mach_port_t *server_portp)
+{
+ server_t *serverp;
+ bootstrap_info_t *bootstrap;
+
+ bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ debug("Server create attempt: \"%s\" bootstrap %x",
+ server_cmd, bootstrap_port);
+
+ /* No forwarding allowed for this call - security risk (we run as root) */
+ if (!bootstrap || !active_bootstrap(bootstrap)) {
+ debug("Server create: \"%s\": invalid bootstrap %x",
+ server_cmd, bootstrap_port);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ /* only same uid (or root client) */
+ if (sectoken.val[0] && sectoken.val[0] != server_uid) {
+ log("Server create: \"%s\": invalid security token (%d != %d)",
+ server_cmd, sectoken.val[0], server_uid);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ serverp = new_server(
+ bootstrap,
+ server_cmd,
+ server_uid,
+ (on_demand) ? DEMAND : RESTARTABLE);
+ setup_server(serverp);
+
+ info("New server %x in bootstrap %x: \"%s\"",
+ serverp->port, bootstrap_port, server_cmd);
+ *server_portp = serverp->port;
+ return BOOTSTRAP_SUCCESS;
+}
+
+/*
+ * kern_return_t
+ * bootstrap_unprivileged(mach_port_t bootstrap_port,
+ * mach_port_t *unpriv_port)
+ *
+ * Given a bootstrap port, return its unprivileged equivalent. If
+ * the port is already unprivileged, another reference to the same
+ * port is returned.
+ *
+ * This is most often used by servers, which are launched with their
+ * bootstrap port set to the privileged port for the server, to get
+ * an unprivileged version of the same port for use by its unprivileged
+ * children (or any offspring that it does not want to count as part
+ * of the "server" for mach_init registration and re-launch purposes).
+ */
+kern_return_t
+x_bootstrap_unprivileged(
+ mach_port_t bootstrap_port,
+ mach_port_t *unpriv_portp)
+{
+ bootstrap_info_t *bootstrap;
+
+ debug("Get unprivileged attempt for bootstrap %x", bootstrap_port);
+
+ bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ if (!bootstrap || !active_bootstrap(bootstrap)) {
+ debug("Get unprivileged: invalid bootstrap %x", bootstrap_port);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+
+ *unpriv_portp = bootstrap->bootstrap_port;
+
+ debug ("Get unpriv bootstrap %x returned for bootstrap %x",
+ bootstrap->bootstrap_port, bootstrap_port);
+ return BOOTSTRAP_SUCCESS;
+}
+
+
/*
* kern_return_t
* bootstrap_check_in(mach_port_t bootstrap_port,
mach_port_t *service_portp)
{
kern_return_t result;
+ mach_port_t previous;
service_t *servicep;
server_t *serverp;
bootstrap_info_t *bootstrap;
- bootstrap = lookup_bootstrap_by_port(bootstrap_port);
serverp = lookup_server_by_port(bootstrap_port);
- if (serverp == NULL) {
- debug("bootstrap_check_in service %s has no server",
- service_name);
- return BOOTSTRAP_NOT_PRIVILEGED;
- }
+ bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ debug("Service checkin attempt for service %s bootstrap %x",
+ service_name, bootstrap_port);
+
servicep = lookup_service_by_name(bootstrap, service_name);
if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
debug("bootstrap_check_in service %s unknown%s", service_name,
forward_ok ? " forwarding" : "");
- result = BOOTSTRAP_UNKNOWN_SERVICE;
- goto forward;
+ return forward_ok ?
+ bootstrap_check_in(
+ inherited_bootstrap_port,
+ service_name,
+ service_portp) :
+ BOOTSTRAP_UNKNOWN_SERVICE;
}
if (servicep->server != NULL && servicep->server != serverp) {
debug("bootstrap_check_in service %s not privileged",
service_name);
return BOOTSTRAP_SERVICE_ACTIVE;
}
- log("Checkin service %s", service_name);
+ debug("Checkin service %s for bootstrap %x", service_name,
+ bootstrap->bootstrap_port);
ASSERT(servicep->isActive == FALSE);
servicep->isActive = TRUE;
+
+ if (servicep->server != NULL_SERVER) {
+ /* registered server - service needs backup */
+ serverp->activity++;
+ serverp->active_services++;
+ result = mach_port_request_notification(
+ mach_task_self(),
+ servicep->port,
+ MACH_NOTIFY_PORT_DESTROYED,
+ 0,
+ backup_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_request_notification");
+ } else {
+ /* one time use/created service */
+ servicep->servicetype = REGISTERED;
+ result = mach_port_request_notification(
+ mach_task_self(),
+ servicep->port,
+ MACH_NOTIFY_DEAD_NAME,
+ 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_request_notification");
+ else if (previous != MACH_PORT_NULL) {
+ debug("deallocating old notification port (%x) for checked in service %x",
+ previous, servicep->port);
+ result = mach_port_deallocate(
+ mach_task_self(),
+ previous);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_deallocate");
+ }
+ }
+
+ info("Check-in service %x in bootstrap %x: %s",
+ servicep->port, servicep->bootstrap->bootstrap_port, servicep->name);
+
*service_portp = servicep->port;
- info("Check-in port %d for service %s\n",
- servicep->port, servicep->name);
return BOOTSTRAP_SUCCESS;
- forward:
- return forward_ok
- ? bootstrap_check_in(inherited_bootstrap_port,
- service_name,
- service_portp)
- : result;
}
/*
name_t service_name,
mach_port_t service_port)
{
+ kern_return_t result;
service_t *servicep;
server_t *serverp;
bootstrap_info_t *bootstrap;
mach_port_t old_port;
- bootstrap = lookup_bootstrap_by_port(bootstrap_port);
- ASSERT(canSend(service_port));
- debug("Register attempt for service %s port %d",
+ debug("Register attempt for service %s port %x",
service_name, service_port);
+ /*
+ * Validate the bootstrap.
+ */
+ bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ if (!bootstrap || !active_bootstrap(bootstrap))
+ return BOOTSTRAP_NOT_PRIVILEGED;
+
/*
* If this bootstrap port is for a server, or it's an unprivileged
* bootstrap can't register the port.
if (servicep && servicep->server && servicep->server != serverp)
return BOOTSTRAP_NOT_PRIVILEGED;
- if (serverp)
- bootstrap_port = bootstrap->bootstrap_port;
- else if (bootstrap_port != bootstrap->bootstrap_port)
- return BOOTSTRAP_NOT_PRIVILEGED;
-
if (servicep == NULL || servicep->bootstrap != bootstrap) {
servicep = new_service(bootstrap,
service_name,
NULL_SERVER);
debug("Registered new service %s", service_name);
} else {
- if (servicep->isActive) {
- debug("Register: service %s already active, port %d",
+ if (servicep->isActive) {
+ debug("Register: service %s already active, port %x",
servicep->name, servicep->port);
ASSERT(!canReceive(servicep->port));
return BOOTSTRAP_SERVICE_ACTIVE;
}
- old_port = servicep->port;
+ old_port = servicep->port;
+ if (servicep->servicetype == DECLARED) {
+ servicep->servicetype = REGISTERED;
+
+ if (servicep->server) {
+ ASSERT(servicep->server == serverp);
+ ASSERT(active_server(serverp));
+ servicep->server = NULL_SERVER;
+ serverp->activity++;
+ }
+
+ result = mach_port_mod_refs(
+ mach_task_self(),
+ old_port,
+ MACH_PORT_RIGHT_RECEIVE,
+ -1);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_mod_refs");
+ }
+ result = mach_port_deallocate(
+ mach_task_self(),
+ old_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_mod_refs");
+
servicep->port = service_port;
- msg_destroy_port(old_port);
servicep->isActive = TRUE;
- log("Re-registered inactive service %s", service_name);
+ debug("Re-registered inactive service %x bootstrap %x: %s",
+ servicep->port, servicep->bootstrap->bootstrap_port, service_name);
}
- debug("Registering port %d for service %s\n",
- servicep->port,
- servicep->name);
+
+ /* detect the new service port going dead */
+ result = mach_port_request_notification(
+ mach_task_self(),
+ service_port,
+ MACH_NOTIFY_DEAD_NAME,
+ 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old_port);
+ if (result != KERN_SUCCESS) {
+ debug("Can't request notification on service %x bootstrap %x: %s",
+ service_port, servicep->bootstrap->bootstrap_port, "must be dead");
+ delete_service(servicep);
+ return BOOTSTRAP_SUCCESS;
+ } else if (old_port != MACH_PORT_NULL) {
+ debug("deallocating old notification port (%x) for service %x",
+ old_port, service_port);
+ result = mach_port_deallocate(
+ mach_task_self(),
+ old_port);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_deallocate");
+ }
+ info("Registered service %x bootstrap %x: %s",
+ servicep->port, servicep->bootstrap->bootstrap_port, servicep->name);
return BOOTSTRAP_SUCCESS;
}
servicep = lookup_service_by_name(bootstrap, service_name);
if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
if (forward_ok) {
-#if DEBUG
debug("bootstrap_look_up service %s forwarding",
service_name);
-#endif DEBUG
return bootstrap_look_up(inherited_bootstrap_port,
service_name,
service_portp);
} else {
-#if DEBUG
debug("bootstrap_look_up service %s unknown",
service_name);
-#endif DEBUG
return BOOTSTRAP_UNKNOWN_SERVICE;
}
}
- if (!canSend(servicep->port)) {
- error("Mysterious loss of send rights on port %d, "
- "deleting service %s",
- servicep->port,
- servicep->name);
- delete_service(servicep);
- return BOOTSTRAP_UNKNOWN_SERVICE;
- }
*service_portp = servicep->port;
-#if DEBUG
- debug("Lookup returns port %d for service %s\n",
+ debug("Lookup returns port %x for service %s",
servicep->port,
servicep->name);
-#endif DEBUG
return BOOTSTRAP_SUCCESS;
}
service_ports[i] = MACH_PORT_NULL;
}
}
-#if DEBUG
debug("bootstrap_look_up_array returns %d ports", service_names_cnt);
-#endif DEBUG
*service_portsp = service_ports;
return BOOTSTRAP_SUCCESS;
}
+/*
+ * kern_return_t
+ * bootstrap_parent(mach_port_t bootstrap_port,
+ * mach_port_t *parent_port);
+ *
+ * Given a bootstrap subset port, return the parent bootstrap port.
+ * If the specified bootstrap port is already the root subset,
+ * MACH_PORT_NULL will be returned.
+ *
+ * Errors:
+ * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running
+ * with an effective user id of root (as determined by the security
+ * token in the message trailer).
+ */
+kern_return_t
+x_bootstrap_parent(
+ mach_port_t bootstrap_port,
+ security_token_t sectoken,
+ mach_port_t *parent_port)
+{
+#if 0
+ bootstrap_info_t *bootstrap;
+
+ debug("Parent attempt for bootstrap %x", bootstrap_port);
+
+ bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ if (!bootstrap || !active_bootstrap(bootstrap)) {
+ debug("Parent attempt for bootstrap %x: invalid bootstrap",
+ bootstrap_port);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ if (sectoken.val[0]) {
+ log("Bootstrap parent for bootstrap %x: invalid security token (%d)",
+ bootstrap_port, sectoken.val[0]);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ debug("Returning bootstrap parent %x for bootstrap %x",
+ bootstrap->parent->bootstrap_port, bootstrap_port);
+ *parent_port = bootstrap->parent->bootstrap_port;
+ return BOOTSTRAP_SUCCESS;
+#else
+ debug("bootstrap parent for bootstrap %x: not implemented",
+ bootstrap_port);
+ return BOOTSTRAP_NOT_PRIVILEGED;
+#endif
+}
+
/*
* kern_return_t
* bootstrap_status(mach_port_t bootstrap_port,
* name_t service_name,
- * boolean_t *service_active);
+ * bootstrap_status_t *service_active);
*
- * Returns: service_active is true if service is available.
+ * Returns: service_active indicates if service is available.
*
* Errors: Returns appropriate kernel errors on rpc failure.
* Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
*/
kern_return_t
x_bootstrap_status(
- mach_port_t bootstrap_port,
- name_t service_name,
- boolean_t *service_active)
+ mach_port_t bootstrap_port,
+ name_t service_name,
+ bootstrap_status_t *service_active)
{
service_t *servicep;
bootstrap_info_t *bootstrap;
service_name,
service_active);
} else {
-#if DEBUG
debug("bootstrap_status service %s unknown",
service_name);
-#endif DEBUG
return BOOTSTRAP_UNKNOWN_SERVICE;
}
}
- *service_active = servicep->isActive;
-#if DEBUG
+ *service_active = bsstatus(servicep);
+
debug("bootstrap_status server %s %sactive", service_name,
servicep->isActive ? "" : "in");
-#endif DEBUG
return BOOTSTRAP_SUCCESS;
}
* int *service_names_cnt,
* name_array_t *server_names,
* int *server_names_cnt,
- * bool_array_t *service_actives,
+ * bootstrap_status_array_t *service_actives,
* int *service_active_cnt);
*
* Returns bootstrap status for all known services.
*/
kern_return_t
x_bootstrap_info(
- mach_port_t bootstrap_port,
- name_array_t *service_namesp,
- unsigned int *service_names_cnt,
- name_array_t *server_namesp,
- unsigned int *server_names_cnt,
- bool_array_t *service_activesp,
- unsigned int *service_actives_cnt)
+ mach_port_t bootstrap_port,
+ name_array_t *service_namesp,
+ unsigned int *service_names_cnt,
+ name_array_t *server_namesp,
+ unsigned int *server_names_cnt,
+ bootstrap_status_array_t *service_activesp,
+ unsigned int *service_actives_cnt)
{
kern_return_t result;
unsigned int i, cnt;
bootstrap_info_t *bootstrap;
name_array_t service_names;
name_array_t server_names;
- bool_array_t service_actives;
+ bootstrap_status_array_t service_actives;
bootstrap = lookup_bootstrap_by_port(bootstrap_port);
}
for ( i = 0, servicep = services.next
- ; i < nservices
+ ; i < cnt
; servicep = servicep->next)
{
if ( lookup_service_by_name(bootstrap, servicep->name)
debug("bootstrap info service %s %sactive",
servicep->name, servicep->isActive ? "" : "in");
}
- service_actives[i] = servicep->isActive;
+ service_actives[i] = bsstatus(servicep);
i++;
}
*service_namesp = service_names;
bootstrap_info_t *bootstrap;
bootstrap_info_t *subset;
mach_port_t new_bootstrap_port;
+ mach_port_t previous;
+
+ debug("Subset create attempt: bootstrap %x, requestor: %x",
+ bootstrap_port, requestor_port);
bootstrap = lookup_bootstrap_by_port(bootstrap_port);
+ if (!bootstrap || !active_bootstrap(bootstrap))
+ return BOOTSTRAP_NOT_PRIVILEGED;
- result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &new_bootstrap_port);
+ result = mach_port_allocate(
+ mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &new_bootstrap_port);
if (result != KERN_SUCCESS)
kern_fatal(result, "mach_port_allocate");
- result = mach_port_insert_right(mach_task_self(), new_bootstrap_port, new_bootstrap_port, MACH_MSG_TYPE_MAKE_SEND);
+
+ result = mach_port_insert_right(
+ mach_task_self(),
+ new_bootstrap_port,
+ new_bootstrap_port,
+ MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS)
kern_fatal(result, "failed to insert send right");
- result = mach_port_move_member(mach_task_self(), new_bootstrap_port, bootstrap_port_set);
+ result = mach_port_insert_member(
+ mach_task_self(),
+ new_bootstrap_port,
+ bootstrap_port_set);
if (result != KERN_SUCCESS)
kern_fatal(result, "port_set_add");
subset = new_bootstrap(bootstrap, new_bootstrap_port, requestor_port);
+
+ result = mach_port_request_notification(
+ mach_task_self(),
+ requestor_port,
+ MACH_NOTIFY_DEAD_NAME,
+ 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ if (result != KERN_SUCCESS) {
+ kern_error(result, "mach_port_request_notification");
+ mach_port_deallocate(mach_task_self(), requestor_port);
+ subset->requestor_port = MACH_PORT_NULL;
+ deactivate_bootstrap(subset);
+ } else if (previous != MACH_PORT_NULL) {
+ debug("deallocating old notification port (%x) for requestor %x",
+ previous, requestor_port);
+ result = mach_port_deallocate(
+ mach_task_self(),
+ previous);
+ if (result != KERN_SUCCESS)
+ kern_fatal(result, "mach_port_deallocate");
+ }
+
+ info("Created bootstrap subset %x parent %x requestor %x",
+ new_bootstrap_port, bootstrap_port, requestor_port);
*subset_port = new_bootstrap_port;
- debug("bootstrap_subset new bootstrap %d", new_bootstrap_port);
return BOOTSTRAP_SUCCESS;
}
name_t service_name,
mach_port_t *service_port)
{
+ server_t *serverp;
service_t *servicep;
bootstrap_info_t *bootstrap;
kern_return_t result;
- mach_port_t previous;
bootstrap = lookup_bootstrap_by_port(bootstrap_port);
- ASSERT(bootstrap);
- debug("Service creation attempt for service %s", service_name);
+ if (!bootstrap || !active_bootstrap(bootstrap))
+ return BOOTSTRAP_NOT_PRIVILEGED;
+
+ debug("Service creation attempt for service %s bootstrap %x",
+ service_name, bootstrap_port);
servicep = lookup_service_by_name(bootstrap, service_name);
if (servicep) {
return BOOTSTRAP_NAME_IN_USE;
}
+ serverp = lookup_server_by_port(bootstrap_port);
+
result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, service_port);
if (result != KERN_SUCCESS)
kern_fatal(result, "port_allocate");
result = mach_port_insert_right(mach_task_self(), *service_port, *service_port, MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS)
kern_fatal(result, "failed to insert send right");
-#if notyet
- result = port_set_backup(mach_task_self(), *service_port, backup_port,
- &previous);
- if (result != KERN_SUCCESS)
- kern_fatal(result, "port_set_backup");
- info("Declared port %d for service %s", *service_port,
- service_name);
-#endif /*notyet */
+
+ if (serverp)
+ serverp->activity++;
servicep = new_service(bootstrap,
service_name,
*service_port,
!ACTIVE,
DECLARED,
- NULL_SERVER);
+ serverp);
- log("Created new service %s", service_name);
+ info("Created new service %x in bootstrap %x: %s",
+ servicep->port, bootstrap->bootstrap_port, service_name);
return BOOTSTRAP_SUCCESS;
}
+++ /dev/null
-services FreeService1 FreeService2;
-# server testServer services BndService3 BndMachService2=2;
-restartable server priority=16 "/NextApps/Terminal" services TerminalService;
-server "/usr/bin/sleep 10" services SleepService;
-self priority=15 Service=2;
-services NetMsgService=0 EnvironService=1 WindowService=3;
-forward;
+++ /dev/null
-services foobar;
+++ /dev/null
-CFLAGS = -g -I..
-
-all: boot_subset testServer listServer
-
-boot_subset: boot_subset.o
- cc -o boot_subset boot_subset.o
-
-testServer: testServer.o bootstrapUser.o
- cc -o testServer testServer.o bootstrapUser.o
-
-listServer: listServer.o bootstrapUser.o
- cc -o listServer listServer.o bootstrapUser.o
-
-
-bootstrapUser.o: ../bootstrapUser.c
- cc -c -g ../bootstrapUser.c
-
-clean:
- rm -f *.o testServer listServer
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * Bootstrap subset exercise.
- *
- * do {
- * create a subset port with requestor = req_port;
- * register "foo" on subset_port;
- * deallocate req_port;
- * } until error;
- */
-
-#import <sys/types.h>
-#import <mach.h>
-#import <servers/bootstrap.h>
-#import <libc.h>
-#import <mach_error.h>
-
-void log_boot_servers(port_t boot_port);
-
-int main(int argc, char **argv)
-{
- kern_return_t krtn;
- port_t subset_port;
- port_t requestor_port;
- port_t foo_port;
- int loop = 0;
- int deallocate_subset = 0;
-
- if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 'r') {
- port_t newboot;
-
- krtn = bootstrap_look_up(bootstrap_port, &argv[1][2], &newboot);
- if (krtn) {
- mach_error("bootstrap lookup", krtn);
- exit(1);
- }
- bootstrap_port = newboot;
- --argc; ++argv;
- }
- if(argc >= 2) {
- if(argv[1][0] == '-' && argv[1][0] == 'd')
- deallocate_subset = 1;
- }
-
- /*
- * Allocate some resources.
- */
- krtn = port_allocate(task_self(), &foo_port);
- if(krtn) {
- mach_error("port_allocate", krtn);
- exit(1);
- }
-
- do {
- krtn = port_allocate(task_self(), &requestor_port);
- if(krtn) {
- mach_error("port_allocate", krtn);
- exit(1);
- }
- krtn = bootstrap_subset(bootstrap_port,
- requestor_port, /* requestor */
- &subset_port);
- if(krtn) {
- mach_error("bootstrap_subset", krtn);
- break;
- }
- printf("Loop %d, prior to bootstrap_register:\n", loop);
- log_boot_servers(subset_port);
-
- krtn = bootstrap_register(subset_port,
- "foo",
- foo_port);
- if(krtn) {
- mach_error("bootstrap_register (subset)", krtn);
- exit(1);
- }
- printf("Loop %d, after bootstrap_register:\n", loop);
- log_boot_servers(subset_port);
-
- /*
- * Delete requestor_port, subset should go away.
- */
- krtn = port_deallocate(task_self(), requestor_port);
- if(krtn) {
- mach_error("port_deallocate", krtn);
- exit(1);
- }
-
- if(deallocate_subset) {
- krtn = port_deallocate(task_self(), subset_port);
- if(krtn) {
- mach_error("port_deallocate(subset)", krtn);
- exit(1);
- }
- }
- loop++;
- } while(krtn == KERN_SUCCESS);
-
- printf("...done\n");
- exit(0);
-}
-
-void log_boot_servers(port_t boot_port)
-{
- int i;
- name_array_t service_names;
- unsigned int service_cnt;
- name_array_t server_names;
- unsigned int server_cnt;
- bool_array_t service_active;
- unsigned int service_active_cnt;
- kern_return_t krtn;
-
- krtn = bootstrap_info(boot_port,
- &service_names,
- &service_cnt,
- &server_names,
- &server_cnt,
- &service_active,
- &service_active_cnt);
- if (krtn != BOOTSTRAP_SUCCESS)
- printf("ERROR: info failed: %d", krtn);
- else {
- printf("log_boot_server: service_cnt = %d\n", service_cnt);
- for (i = 0; i < service_cnt; i++)
- printf("Name: %-15s Server: %-15s "
- "Active: %-4s",
- service_names[i],
- server_names[i][0] == '\0' ?
- "Unknown" : server_names[i],
- service_active[i] ? "Yes\n" : "No\n");
- }
-}
-
-
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-#import "bootstrap.h"
-
-#import <mach.h>
-#import <stdarg.h>
-#import <stdio.h>
-#import <sys/boolean.h>
-
-#define NELEM(x) (sizeof(x)/sizeof(x[0]))
-#define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
-
-print(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-error(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-
-main()
-{
- kern_return_t result;
- port_t bootstrap_port;
- name_array_t service_names;
- unsigned service_cnt, server_cnt, service_active_cnt;
- name_array_t server_names;
- boolean_t *service_actives;
- int i;
-
- result = task_get_bootstrap_port(task_self(), &bootstrap_port);
- if (result != KERN_SUCCESS) {
- error("Couldn't get bootstrap port: %d", result);
- exit(1);
- }
- if (bootstrap_port == PORT_NULL) {
- error("Invalid bootstrap port");
- exit(1);
- }
-
- result = bootstrap_info(bootstrap_port, &service_names, &service_cnt,
- &server_names, &server_cnt, &service_actives, &service_active_cnt);
- if (result != BOOTSTRAP_SUCCESS)
- error("info failed: %d", result);
- else {
- for (i = 0; i < service_cnt; i++)
- print("Name: %-15s Server: %-15s Active: %-4s",
- service_names[i],
- server_names[i][0] == '\0' ? "Unknown" : server_names[i],
- service_actives[i] ? "Yes" : "No");
- }
-
- exit(0);
-}
-
-
-
-
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-#import "bootstrap.h"
-
-#import <mach.h>
-#import <stdarg.h>
-#import <stdio.h>
-#import <sys/boolean.h>
-
-#define NELEM(x) (sizeof(x)/sizeof(x[0]))
-#define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
-
-print(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-error(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-
-main()
-{
- kern_return_t result;
- port_t bootstrap_port, port, myport;
- port_type_t ptype;
- port_t *mach_ports;
- port_t *ports;
- unsigned port_cnt;
- unsigned mach_ports_cnt;
- name_t name_array[4];
- boolean_t all_known;
- port_t unpriv_port;
- port_t subset_port;
- port_t sub_reg_port;
- boolean_t active;
- name_array_t service_names;
- unsigned service_cnt, server_cnt, service_active_cnt;
- name_array_t server_names;
- boolean_t *service_actives;
- int i;
-
- print("test server running");
- result = task_get_bootstrap_port(task_self(), &bootstrap_port);
- if (result != KERN_SUCCESS) {
- error("Couldn't get bootstrap port: %d", result);
- exit(1);
- } else
- print("Bootstrap port is %d", bootstrap_port);
- if (bootstrap_port == PORT_NULL) {
- error("Invalid bootstrap port");
- exit(1);
- }
-
- /*
- * Try a checkin
- */
- print("Checkin test 1");
- result = bootstrap_check_in(bootstrap_port, "FreeService1", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Checkin failed: %d", result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- else
- print("Checkin returned port type 0x%x", ptype);
- /*
- * Try a status request
- */
- result = bootstrap_status(bootstrap_port, "FreeService1", &active);
- if (result != BOOTSTRAP_SUCCESS)
- error("Status failed: %d", result);
- else if (active != TRUE)
- error("Service shown inactive");
- }
-
- /*
- * Try a lookup
- */
- print("lookup test");
- result = bootstrap_look_up(bootstrap_port, "FreeService2", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("lookup failed: %d", result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- else
- print("Lookup returned port type 0x%x", ptype);
- /*
- * Try a status request
- */
- result = bootstrap_status(bootstrap_port, "FreeService2", &active);
- if (result != BOOTSTRAP_SUCCESS)
- error("Status failed: %d", result);
- else if (active != FALSE)
- error("Service shown active");
- }
-
- /*
- * Test that mach ports are initialized
- */
- print("mach ports test");
- result = mach_ports_lookup(task_self(), &mach_ports, &mach_ports_cnt);
- if (result != KERN_SUCCESS)
- error("mach_ports_lookup failed: %d", result);
- else {
- result = bootstrap_look_up(bootstrap_port, "NetMsgService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Lookup of NetMsgService failed: %d", result);
- else if (port != mach_ports[0])
- error("mach ports not setup correctly for NetMsgService");
-
- result = bootstrap_look_up(bootstrap_port, "EnvironService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Lookup of EnvironService failed: %d", result);
- else if (port != mach_ports[1])
- error("mach ports not setup correctly for EnvironService");
-
- result = bootstrap_look_up(bootstrap_port, "Service", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Lookup of Service failed: %d", result);
- else if (port != mach_ports[2])
- error("mach ports not setup correctly for Service");
-
- result = bootstrap_look_up(bootstrap_port, "WindowService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Lookup of WindowService failed: %d", result);
- else if (port != mach_ports[3])
- error("mach ports not setup correctly for WindowService");
- }
-
- /*
- * Try doing a checkin with the old service interface
- */
- result = service_checkin(mach_ports[2], mach_ports[1], &myport);
- if (result != KERN_SUCCESS)
- error("service checkin failed: %d", result);
- else {
- result = port_type(task_self(), myport, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- else
- print("Checkin returned port type 0x%x", ptype);
- }
-
- /*
- * Try a register
- */
- print("register test");
- print("...Dynamic creation");
- result = port_allocate(task_self(), &myport);
- if (result != KERN_SUCCESS)
- error("couldn't allocate port: %d", result);
- else {
- result = bootstrap_register(bootstrap_port, "NewService", myport);
- if (result != BOOTSTRAP_SUCCESS)
- error("Couldn't register port: %d", result);
- else {
-
- /*
- * Try a lookup on just registered port
- */
- result = bootstrap_look_up(bootstrap_port, "NewService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("lookup failed: %d", result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- else {
- print("Lookup returned port type 0x%x", ptype);
- if (port != myport)
- error("lookup didn't match register");
- }
- }
-
- /*
- * Try re-registering service name
- */
- result = bootstrap_register(bootstrap_port, "NewService", myport);
- if (result != BOOTSTRAP_SERVICE_ACTIVE)
- error("Unexpected register response: %d", result);
-
- /*
- * Delete the port. This should cause the service to go away
- * in the server.
- */
- port_deallocate(task_self(), myport);
-
- result = bootstrap_look_up(bootstrap_port, "NewService", &port);
- if (result != BOOTSTRAP_UNKNOWN_SERVICE)
- error("service active after port deleted");
- }
- }
-
- print("...Declared service");
- result = port_allocate(task_self(), &myport);
- if (result != KERN_SUCCESS)
- error("couldn't allocate port: %d", result);
- else {
- result = bootstrap_register(bootstrap_port, "FreeService2", myport);
- if (result != BOOTSTRAP_SUCCESS)
- error("Couldn't register port: %d", result);
- else {
-
- /*
- * Try a lookup on just registered port
- */
- result = bootstrap_look_up(bootstrap_port, "FreeService2", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("lookup failed: %d", result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- else {
- print("Lookup returned port type 0x%x", ptype);
- if (port != myport)
- error("lookup didn't match register");
- }
- }
-
- /*
- * Delete the port. This should cause service to revert.
- */
- port_deallocate(task_self(), myport);
-
- result = bootstrap_status(bootstrap_port, "FreeService2", &active);
- if (result != BOOTSTRAP_SUCCESS)
- error("Status failed: %d", result);
- else if (active != FALSE)
- error("Service shown active");
- }
- }
-
- /*
- * Try a checkin on a port bound to Terminal server
- */
- print("Bound checkin test -- Terminal");
- result = bootstrap_check_in(bootstrap_port, "TerminalService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Checkin of TerminalService failed: %d", result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- print("Checkin returned port type 0x%x", ptype);
- }
-
- /*
- * Try a checkin on a port bound to Sleep server
- */
- print("Bound checkin test -- Sleep");
- result = bootstrap_check_in(bootstrap_port, "SleepService", &port);
- if (result != BOOTSTRAP_SUCCESS)
- print("Checkin of SleepService failed (as expected): %d",
- result);
- else {
- result = port_type(task_self(), port, &ptype);
- if (result != KERN_SUCCESS)
- error("port type failed: %d", result);
- error("Checkin returned port type 0x%x(didn't fail!)", ptype);
- }
-
- /*
- * Try a lookup_array
- */
- print("Lookup array test");
-
- strncpy(&name_array[0], "NetMsgService", sizeof(name_array[0]));
- LAST_ELEMENT(name_array[0]) = '\0';
- strncpy(&name_array[1], "EnvironService", sizeof(name_array[1]));
- LAST_ELEMENT(name_array[1]) = '\0';
- strncpy(&name_array[2], "Service", sizeof(name_array[2]));
- LAST_ELEMENT(name_array[2]) = '\0';
- strncpy(&name_array[3], "WindowService", sizeof(name_array[3]));
- LAST_ELEMENT(name_array[3]) = '\0';
-
- result = bootstrap_look_up_array(bootstrap_port, name_array, 4, &ports,
- &port_cnt, &all_known);
- if (result != BOOTSTRAP_SUCCESS)
- error("Lookup array failed: %d", result);
- else {
- print("Port count = %d, all known = %d", port_cnt, all_known);
- for (i = 0; i < 4; i++)
- if (ports[i] != mach_ports[i])
- error("port mismatch on port %d", i);
- }
-
- /*
- * Get an unprivileged port
- */
- print("Unprivileged port test");
- result = port_allocate(task_self(), &myport);
- result = bootstrap_get_unpriv_port(bootstrap_port, &unpriv_port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Couldn't get unpriv port: %d", result);
- else {
- /*
- * Try doing an unpriv operation
- */
- result = bootstrap_look_up(unpriv_port, "FreeService2", &port);
- if (result != BOOTSTRAP_SUCCESS)
- error("lookup failed: %d", result);
- /*
- * Try doing a privileged operation
- */
- result = bootstrap_register(unpriv_port, "ANewService", myport);
- if (result != BOOTSTRAP_NOT_PRIVILEGED)
- error("Unexpected register port response: %d", result);
-
- /*
- * Try creating a subset port.
- */
- result = bootstrap_subset(unpriv_port, task_self(),
- &subset_port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Couldn't get subset port from unpriv %d",
- result);
- }
-
- /*
- * Get a subset port.
- */
- print("Subset port test");
- result = bootstrap_subset(bootstrap_port, task_self(), &subset_port);
- if (result != BOOTSTRAP_SUCCESS)
- error("Couldn't get subset port: %d", result);
- else {
-
- /*
- * Register a port.
- */
- result = port_allocate(task_self(), &sub_reg_port);
- if (result != KERN_SUCCESS)
- error("port_allocate of sub_reg_port failed %d",
- result);
- result = bootstrap_register(subset_port, "SubsetReg",
- sub_reg_port);
- if (result != BOOTSTRAP_SUCCESS)
- error("register of SubsetReg failed on subset port %d",
- result);
- /*
- * Check that port registered only in subset.
- */
- result = bootstrap_status(bootstrap_port, "SubsetReg",
- &active);
- if (result != BOOTSTRAP_UNKNOWN_SERVICE)
- error("status of SubsetReg ok on bootstrap! %d",
- result);
- result = bootstrap_status(subset_port, "SubsetReg",
- &active);
- if (result != BOOTSTRAP_SUCCESS)
- error("status of SubsetReg failed on subset port %d",
- result);
- if (!active)
- error("SubsetReg isn't active");
-
-
- /*
- * Try an info request.
- */
- print("Subset info request");
- result = bootstrap_info(subset_port, &service_names,
- &service_cnt,
- &server_names, &server_cnt, &service_actives,
- &service_active_cnt);
- if (result != BOOTSTRAP_SUCCESS)
- error("info failed: %d", result);
- else {
- for (i = 0; i < service_cnt; i++)
- print("Name: %s Server: %s Active: %s",
- service_names[i],
- server_names[i][0] == '\0'
- ? "Unknown"
- : server_names[i],
- service_actives[i] ? "Yes" : "No");
- }
- }
-
- /*
- * Try an info request
- */
- print("Info test");
- result = bootstrap_info(bootstrap_port, &service_names, &service_cnt,
- &server_names, &server_cnt, &service_actives, &service_active_cnt);
- if (result != BOOTSTRAP_SUCCESS)
- error("info failed: %d", result);
- else {
- for (i = 0; i < service_cnt; i++)
- print("Name: %s Server: %s Active: %s", service_names[i],
- server_names[i][0] == '\0' ? "Unknown" : server_names[i],
- service_actives[i] ? "Yes" : "No");
- }
-
- exit(0);
-}
-
-
-
CFILES = mkfile.c
-OTHERSRCS = Makefile.preamble
+OTHERSRCS = Makefile.preamble Makefile.postamble mkfile.8
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
--- /dev/null
+after_install:
+ install -d $(DSTROOT)/usr/share/man/man8
+ install -c -m 444 mkfile.8 $(DSTROOT)/usr/share/man/man8
--- /dev/null
+.\" (c) 1997 Apple Computer, Inc.
+.TH MKFILE 8 "1 September 1997"
+.SH NAME
+mkfile \- create a file
+.SH SYNOPSIS
+.B mkfile
+.RB [ " -nv " ]
+.I size\c
+[\c
+.BR b | k | m | g\c
+]
+.IR filename " .\|.\|."
+.SH DESCRIPTION
+.B mkfile
+creates one or more files that are suitable for use as
+.SM NFS-\s0mounted
+swap areas. The sticky bit is set, and
+the file is padded with zeroes by default.
+Non-root users must set the sticky bit using
+chmod(1).
+The default size unit is bytes, but the following suffixes
+may be used to multiply by the given factor:
+.B b
+(512),
+.B k
+(1024),
+.B m
+(1048576), and
+.B g
+(1073741824).
+.SH OPTIONS
+.TP
+.B \-n
+Create an empty
+.IR filename .
+The size is noted, but disk blocks aren't allocated until data is
+written to them.
+.TP
+.B \-v
+Verbose. Report the names and sizes of created files.
+.SH WARNING
+If a client's swap file is removed and recreated, it must be
+re-exported before the client will be able to access it.
+This action may only be done when the client is not running.
+.SH "SEE ALSO"
+.TP
+chmod(2), stat(2), exportfs(8), sticky(8)
# Note: on MS Windows, executables, have an extension, so rules and dependencies
# for generated tools should use $(EXECUTABLE_EXT) on the end.
+SHAREDIR = /usr/share
+MANDIR = $(SHAREDIR)/man/man8
+MANPAGE = nologin.8
+
nologin: nologin.sh
$(CP) nologin.sh ${SYM_DIR}/nologin
after_install::
$(CP) -p ${SYM_DIR}/nologin $(DSTROOT)$(INSTALLDIR)/nologin
$(CHMOD) 555 $(DSTROOT)$(INSTALLDIR)/nologin
+ $(MKDIRS) $(DSTROOT)$(MANDIR)
+ $(CP) -f $(MANPAGE) $(DSTROOT)$(MANDIR)/$(MANPAGE)
+ $(CHMOD) og-w $(DSTROOT)$(MANDIR)/$(MANPAGE)
+.\" $OpenBSD: nologin.8,v 1.3 1997/02/16 04:15:32 downsj Exp $
+.\" $NetBSD: nologin.8,v 1.3 1995/03/18 14:59:09 cgd Exp $
+.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\"
.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
.\"
-.Dd June 19, 1993
+.Dd February 15, 1997
.Dt NOLOGIN 8
-.Os BSD 4.4
+.Os
.Sh NAME
.Nm nologin
.Nd politely refuse a login
exits non-zero.
It is intended as a replacement shell field for accounts that
have been disabled.
+.Pp
+If the file
+.Pa /etc/nologin.txt
+exists,
+.Nm nologin
+displays its contents to the user instead of the default message.
.Sh SEE ALSO
.Xr login 1
.Sh HISTORY
.IR name
can be any string. In practice, not all strings will be accepted.
Old world machines have a fixed set of Open Firmware variables.
-New World machines can create new varibles as desired. Some variables
-require adminstrator privilege to get or set.
+New World machines can create new variables as desired. Some variables
+require administrator privilege to get or set.
.LP
The given
.IR value
example% nvram boot-args="-s rd=*hd:10"
.RE
.LP
-Set the boot-args variable to "-s rd=*hd:10". This would specifiy
+Set the boot-args variable to "-s rd=*hd:10". This would specify
single user mode with the root device in hard drive partition 10.
.LP
.RS
example% nvram my-variable="String One%00String Two%00%00"
.RE
.LP
-Create a new variable, my-variable, containging a list of two
+Create a new variable, my-variable, containing a list of two
C-strings that is terminated by a NUL.
.SH FILES
.PD 0
long cnt, cnt2;
const char *nameString;
char numberBuffer[10];
- char *dataPtr, dataChar;
+ const uint8_t *dataPtr;
+ uint8_t dataChar;
char *dataBuffer = 0;
- char *valueString = 0;
- unsigned long number, length;
+ const char *valueString = 0;
+ uint32_t number, length;
CFTypeID typeID;
// Get the OF variable's name.
NEXTSTEP_INSTALLDIR = /usr/bin
WINDOWS_INSTALLDIR = /Library/Executables
PDO_UNIX_INSTALLDIR = /bin
-LIBS =
+LIBS = -lcurses
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
*/
/*
-cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c
+cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c -lncurses
*/
#define Default_DELAY 1 /* default delay interval */
#include <libc.h>
#include <termios.h>
-#include <bsd/curses.h>
+#include <curses.h>
#include <sys/ioctl.h>
#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
double divisor = DIVISOR;
-struct termios tmode, omode;
int mib[6];
size_t needed;
move(LINES - 1, 0);
refresh();
endwin();
-
- tcsetattr(0, TCSANOW, &omode);
}
set_enable(0);
set_pidcheck(pid, 0);
move(LINES - 1, 0);
refresh();
endwin();
-
- tcsetattr(0, TCSANOW, &omode);
}
printf("sc_usage: ");
if (no_screen_refresh == 0) {
- if (tcgetattr(0, &tmode) < 0) {
- printf("can't get terminal attributes\n");
- exit(1);
- }
- omode = tmode;
-
- tmode.c_lflag &= ~ICANON;
- tmode.c_cc[VMIN] = 0;
- tmode.c_cc[VTIME] = 1;
- if (tcsetattr(0, TCSANOW, &tmode) < 0) {
- printf("can't set terminal attributes\n");
- exit(1);
- }
/* initializes curses and screen (last) */
- initscr();
+ if (initscr() == (WINDOW *) 0)
+ {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ cbreak();
+ timeout(100);
+ noecho();
+
clear();
refresh();
}
/* set up signal handlers */
signal(SIGINT, leave);
signal(SIGQUIT, leave);
+ signal(SIGHUP, leave);
+ signal(SIGTERM, leave);
signal(SIGWINCH, sigwinch);
if (no_screen_refresh == 0)
while (1) {
int i;
int cnt;
- char ibuf[128];
+ char c;
void sample_sc();
for (i = 0; i < (10 * delay) && newLINES == 0; i++) {
if (no_screen_refresh == 0) {
- if ((cnt = read(0, &ibuf, 128)) > 0) {
- int n;
-
- for (n = 0; n < cnt; n++)
- if (ibuf[n] == 'q')
- leave();
- reset_counters();
- break;
- }
+ if ((c = getch()) != ERR && (char)c == 'q')
+ leave();
+ if (c != ERR)
+ reset_counters();
} else
usleep(100000);
sample_sc();
(void)sort_scalls();
if (newLINES) {
- initscr();
+ /*
+ No need to check for initscr error return.
+ We won't get here if it fails on the first call.
+ */
+ endwin();
clear();
refresh();
(uint64_t)((unsigned int)(kd[i].timestamp.tv_nsec));
baseid = debugid & 0xffff0000;
- if (debugid == vfs_lookup) {
+ if (type == vfs_lookup) {
long *sargptr;
if ((ti = find_thread(thread)) == (struct th_info *)0)
continue;
+
if (ti->vfslookup == 1) {
ti->vfslookup++;
memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
*/
if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
- continue;
+ continue;
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (debugid & DBG_FUNC_START)
+ {
+ (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
+ continue;
+ }
+
*sargptr++ = kd[i].arg1;
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
-773
+892
+0x1f000000 DYLD_initialize
+0x1f010000 DYLD_CALL_image_init_routine
+0x1f010004 DYLD_CALL_dependent_init_routine
+0x1f010008 DYLD_CALL_lazy_init_routine
+0x1f01000c DYLD_CALL_module_init_for_library
+0x1f010010 DYLD_CALL_module_init_for_object
+0x1f010014 DYLD_CALL_module_terminator_for_object
+0x1f010018 DYLD_CALL_module_init_for_dylib
+0x1f01001c DYLD_CALL_mod_term_func
+0x1f010020 DYLD_CALL_object_func
+0x1f010024 DYLD_CALL_library_func
+0x1f010028 DYLD_CALL_add_image_func
+0x1f01002c DYLD_CALL_remove_image_func
+0x1f010030 DYLD_CALL_link_object_module_func
+0x1f010034 DYLD_CALL_link_library_module_func
+0x1f010038 DYLD_CALL_link_module_func
+0x1f020000 DYLD_lookup_and_bind_with_hint
+0x1f020004 DYLD_lookup_and_bind_fully
+0x1f020008 DYLD_link_module
+0x1f02000c DYLD_ulink_module
+0x1f020010 DYLD_bind_objc_module
+0x1f020014 DYLD_bind_fully_image_containing_address
+0x1f020018 DYLD_make_delayed_module_initializer_calls
+0x1f02001c DYLD_NSNameOfSymbol
+0x1f020020 DYLD_NSAddressOfSymbol
+0x1f020024 DYLD_NSModuleForSymbol
+0x1f020028 DYLD_NSLookupAndBindSymbolWithHint
+0x1f02002c DYLD_NSLookupSymbolInModule
+0x1f020030 DYLD_NSLookupSymbolInImage
+0x1f020034 DYLD_NSIsSymbolNameDefined
+0x1f020038 DYLD_NSIsSymbolNameDefinedWithHint
+0x1f02003c DYLD_NSIsSymbolNameDefinedInImage
+0x1f020040 DYLD_NSNameOfModule
+0x1f020044 DYLD_NSLibraryNameForModule
+0x1f020048 DYLD_NSAddLibrary
+0x1f02004c DYLD_NSAddLibraryWithSearching
+0x1f020050 DYLD_NSAddImage
+0x1f030000 DYLD_lookup_symbol
+0x1f030004 DYLD_bind_lazy_symbol_reference
+0x1f030008 DYLD_bind_symbol_by_name
+0x1f03000c DYLD_link_in_need_modules
+0x1f040000 DYLD_map_image
+0x1f040004 DYLD_load_executable_image
+0x1f040008 DYLD_load_library_image
+0x1f04000c DYLD_map_library_image
+0x1f040010 DYLD_map_bundle_image
+0x1f040014 DYLD_load_dependent_libraries
+0x1f040018 DYLD_notify_prebinding_agent
+0x1fff0000 LAUNCH_START_FINDER
+0x1fff0100 LAUNCH_START_DOCK
+0x1fff0200 LAUNCH_LSOpen
+0x1fff0204 LAUNCH_LSRegisterItem
+0x1fff0208 LAUNCH_LSGetApplicationAndFlagsForInfo
+0x1fff0300 LAUNCH_CPSLaunch
+0x1fff0304 LAUNCH_CPSRegisterwithServer
+0x1fff0308 LAUNCH_CGSCheckInNewProcess
+0x1fff030c LAUNCH_CPSExecProcess
+0x1fff0310 LAUNCH_APP_EnterEventLoop
+0x1fff0314 LAUNCH_APP_WillOpenUntitled
+0x1fff031c LAUNCH_APP_DidOpenUntitled
+0x1fffffff LAUNCH_END
0xff000104 MSG_mach_notify_port_deleted
0xff000114 MSG_mach_notify_port_destroyed
0xff000118 MSG_mach_notify_no_senders
0xff000658 MSG_vm_allocate_cpm
0xff00065c MSG_host_processors
0xff000660 MSG_host_get_clock_control
-0xff000664 MSG_kmod_create
+0xff000664 MSG_kmod_creat
0xff000668 MSG_kmod_destroy
0xff00066c MSG_kmod_control
0xff000670 MSG_host_get_special_port
0xff002584 MSG_exception_raise
0xff002588 MSG_exception_raise_state
0xff00258c MSG_exception_raise_state_identity
+0xff002648 MSG_samples
+0xff00264c MSG_notices
0xff002bc0 MSG_io_object_get_class
0xff002bc4 MSG_io_object_conforms_to
0xff002bc8 MSG_io_iterator_next
0xff003218 MSG_mach_port_deallocate
0xff00321c MSG_mach_port_get_refs
0xff003220 MSG_mach_port_mod_refs
-0xff003224 MSG_mach_port_allocate_subsystem
0xff003228 MSG_mach_port_set_mscount
0xff00322c MSG_mach_port_get_set_status
0xff003230 MSG_mach_port_move_member
0xff003598 MSG_task_assign_default
0xff00359c MSG_task_get_assignment
0xff0035a0 MSG_task_set_policy
-0xff0035a4 MSG_mach_subsystem_create
0xff003840 MSG_thread_terminate
0xff003844 MSG_act_get_state
0xff003848 MSG_act_set_state
0xff25a8ac MSG_lock_make_stable
0xff25a8b0 MSG_lock_handoff
0xff25a8b4 MSG_lock_handoff_accept
+0xff25abc0 MSG_semaphore_signal
+0xff25abc4 MSG_semaphore_signal_all
+0xff25abc8 MSG_semaphore_wait
+0xff25abcc MSG_semaphore_signal_thread
+0xff25abd0 MSG_semaphore_timedwait
+0xff25abd4 MSG_semaphore_wait_signal
+0xff25abd8 MSG_semaphore_timedwait_signal
0xff3d0904 MSG_bootstrap_ports
0xff3d0908 MSG_bootstrap_arguments
0xff3d090c MSG_bootstrap_environment
0xff3d0910 MSG_bootstrap_completed
+0xffbebdcc MSG_clock_alarm_reply
0x1300000 MACH_vmfault
+0x1300004 MACH_Pageout
0x1400000 MACH_SCHED
0x1400008 MACH_STKHANDOFF
0x1400018 MACH_MKRUNNABLE
0x10c0070 MSC_task_self_trap
0x10c0074 MSC_host_self_trap
0x10c0078 MSC_kern_invalid_#30
-0x10c007c MSC_kern_invalid_#31
+0x10c007c MSC_mach_msg_trap
0x10c0080 MSC_mach_msg_overwrite_trap
0x10c0084 MSC_semaphore_signal_trap
0x10c0088 MSC_semaphore_signal_all_trap
0x10c01fc MSC_kern_invalid_#127
0x1050000 INTERRUPT
0x3010090 VFS_LOOKUP
+0x3020000 P_WrData
+0x3020008 P_RdData
+0x3020020 P_WrMeta
+0x3020028 P_RdMeta
+0x3020040 P_PgOut
+0x3020048 P_PgIn
+0x3020010 P_WrDataAsync
+0x3020018 P_RdDataAsync
+0x3020030 P_WrMetaAsync
+0x3020038 P_RdMetaAsync
+0x3020050 P_PgOutAsync
+0x3020058 P_PgInAsync
+0x3020004 P_WrDataDone
+0x302000C P_RdDataDone
+0x3020024 P_WrMetaDone
+0x302002C P_RdMetaDone
+0x3020044 P_PgOutDone
+0x302004C P_PgInDone
+0x3020014 P_WrDataAsyncDone
+0x302001C P_RdDataAsyncDone
+0x3020034 P_WrMetaAsyncDone
+0x302003C P_RdMetaAsyncDone
+0x3020054 P_PgOutAsyncDone
+0x302005C P_PgInAsyncDone
0x40c0000 BSC_SysCall
0x40c0004 BSC_exit
0x40c0008 BSC_fork
0x40c0014 BSC_open
0x40c0018 BSC_close
0x40c001c BSC_wait4
-0x40c0020 BSC_old_creat
+0x40c0020 BSC_obs_creat
0x40c0024 BSC_link
0x40c0028 BSC_unlink
0x40c002c BSC_obs_execv
0x40c0038 BSC_mknod
0x40c003c BSC_chmod
0x40c0040 BSC_chown
-0x40c0044 BSC_sbreak
-0x40c0048 BSC_getfsstat
+0x40c0044 BSC_obs_break
+0x40c0048 BSC_obs_getfsstat
0x40c004c BSC_old_lseek
0x40c0050 BSC_getpid
0x40c0054 BSC_obs_mount
0x40c008c BSC_fchflags
0x40c0090 BSC_sync
0x40c0094 BSC_kill
-0x40c0098 BSC_old_stat
+0x40c0098 BSC_obs_stat
0x40c009c BSC_getppid
-0x40c00a0 BSC_old_lstat
+0x40c00a0 BSC_obs_lstat
0x40c00a4 BSC_dup
0x40c00a8 BSC_pipe
0x40c00ac BSC_getegid
0x40c00ec BSC_execve
0x40c00f0 BSC_umask
0x40c00f4 BSC_chroot
-0x40c00f8 BSC_old_fstat
-0x40c00fc BSC_old_getkerninfo
-0x40c0100 BSC_old_getpagesize
+0x40c00f8 BSC_obs_fstat
+0x40c00fc BSC_#63
+0x40c0100 BSC_obs_getpagesize
0x40c0104 BSC_msync
0x40c0108 BSC_vfork
0x40c010c BSC_obs_vread
0x40c0110 BSC_obs_vwrite
0x40c0114 BSC_sbrk
0x40c0118 BSC_sstk
-0x40c011c BSC_old_mmap
+0x40c011c BSC_obs_mmap
0x40c0120 BSC_obs_vadvise
0x40c0124 BSC_munmap
0x40c0128 BSC_mprotect
0x40c012c BSC_madvise
-0x40c0130 BSC_obs_vhangup
-0x40c0134 BSC_obs_vlimit
+0x40c0130 BSC_#76
+0x40c0134 BSC_#77
0x40c0138 BSC_mincore
0x40c013c BSC_getgroups
0x40c0140 BSC_setgroups
0x40c0148 BSC_setpgid
0x40c014c BSC_setitimer
0x40c0150 BSC_old_wait
-0x40c0154 BSC_swapon
+0x40c0154 BSC_obs_swapon
0x40c0158 BSC_getitimer
-0x40c015c BSC_old_gethostname
-0x40c0160 BSC_old_sethostname
+0x40c015c BSC_obs_gethostname
+0x40c0160 BSC_obs_sethostname
0x40c0164 BSC_getdtablesize
0x40c0168 BSC_dup2
0x40c016c BSC_#91
0x40c0180 BSC_setpriority
0x40c0184 BSC_socket
0x40c0188 BSC_connect
-0x40c018c BSC_old_accept
+0x40c018c BSC_obs_accept
0x40c0190 BSC_getpriority
0x40c0194 BSC_old_send
0x40c0198 BSC_old_recv
0x40c01a0 BSC_bind
0x40c01a4 BSC_setsockopt
0x40c01a8 BSC_listen
-0x40c01ac BSC_obs_vtimes
-0x40c01b0 BSC_old_sigvec
-0x40c01b4 BSC_old_sigblock
-0x40c01b8 BSC_old_sigsetmask
+0x40c01ac BSC_#107
+0x40c01b0 BSC_obs_sigvec
+0x40c01b4 BSC_obs_sigblock
+0x40c01b8 BSC_obs_sigsetmask
0x40c01bc BSC_sigsuspend
-0x40c01c0 BSC_old_sigstack
-0x40c01c4 BSC_old_recvmsg
-0x40c01c8 BSC_old_sendmsg
-0x40c01cc BSC_obs_vtrace
+0x40c01c0 BSC_obs_sigstack
+0x40c01c4 BSC_obs_recvmsg
+0x40c01c8 BSC_obs_sendmsg
+0x40c01cc BSC_#115
0x40c01d0 BSC_gettimeofday
0x40c01d4 BSC_getrusage
0x40c01d8 BSC_getsockopt
0x40c01e8 BSC_settimeofday
0x40c01ec BSC_fchown
0x40c01f0 BSC_fchmod
-0x40c01f4 BSC_old_recvfrom
-0x40c01f8 BSC_old_setreuid
-0x40c01fc BSC_old_setregid
+0x40c01f4 BSC_obs_recvfrom
+0x40c01f8 BSC_obs_setreuid
+0x40c01fc BSC_obs_setregid
0x40c0200 BSC_rename
-0x40c0204 BSC_old_truncate
-0x40c0208 BSC_old_ftruncate
+0x40c0204 BSC_obs_truncate
+0x40c0208 BSC_obs_ftruncate
0x40c020c BSC_flock
0x40c0210 BSC_mkfifo
0x40c0214 BSC_sendto
0x40c0220 BSC_mkdir
0x40c0224 BSC_rmdir
0x40c0228 BSC_utimes
-0x40c022c BSC_#139
+0x40c022c BSC_futimes
0x40c0230 BSC_adjtime
-0x40c0234 BSC_old_getpeername
-0x40c0238 BSC_old_gethostid
-0x40c023c BSC_old_sethostid
-0x40c0240 BSC_old_getrlimit
-0x40c0244 BSC_old_setrlimit
-0x40c0248 BSC_old_killpg
+0x40c0234 BSC_obs_getpeername
+0x40c0238 BSC_obs_gethostid
+0x40c023c BSC_#143
+0x40c0240 BSC_obs_getrlimit
+0x40c0244 BSC_obs_setrlimit
+0x40c0248 BSC_obs_killpg
0x40c024c BSC_setsid
-0x40c0250 BSC_obs_setquota
-0x40c0254 BSC_obs_quota
-0x40c0258 BSC_old_getsockname
-0x40c025c BSC_#151
+0x40c0250 BSC_#148
+0x40c0254 BSC_#149
+0x40c0258 BSC_obs_getsockname
+0x40c025c BSC_getpgid
0x40c0260 BSC_setprivexec
-0x40c0264 BSC_#153
-0x40c0268 BSC_#154
+0x40c0264 BSC_pread
+0x40c0268 BSC_pwrite
0x40c026c BSC_nfssvc
0x40c0270 BSC_getdirentries
0x40c0274 BSC_statfs
0x40c0278 BSC_fstatfs
0x40c027c BSC_unmount
-0x40c0280 BSC_obs_async_daemon
+0x40c0280 BSC_#160
0x40c0284 BSC_getfh
-0x40c0288 BSC_old_getdomainname
-0x40c028c BSC_old_setdomainname
-0x40c0290 BSC_obs_pcfs_mount
+0x40c0288 BSC_obs_getdomainname
+0x40c028c BSC_obs_setdomainname
+0x40c0290 BSC_#164
0x40c0294 BSC_quotactl
-0x40c0298 BSC_obs_exportfs
+0x40c0298 BSC_#166
0x40c029c BSC_mount
-0x40c02a0 BSC_obs_ustat
+0x40c02a0 BSC_#168
0x40c02a4 BSC_#169
-0x40c02a8 BSC_obs_table
-0x40c02ac BSC_old_wait_3
-0x40c02b0 BSC_obs_rpause
+0x40c02a8 BSC_#170
+0x40c02ac BSC_obs_wait3
+0x40c02b0 BSC_#172
0x40c02b4 BSC_#173
-0x40c02b8 BSC_obs_getdents
+0x40c02b8 BSC_#174
0x40c02bc BSC_#175
0x40c02c0 BSC_add_profil
0x40c02c4 BSC_#177
0x40c02c8 BSC_#178
0x40c02cc BSC_#179
-0x40c02d0 BSC_kdebug
+0x40c02d0 BSC_kdebug_trace
0x40c02d4 BSC_setgid
0x40c02d8 BSC_setegid
0x40c02dc BSC_seteuid
-0x40c02e0 BSC_lfs_bmapv
-0x40c02e4 BSC_lfs_markv
-0x40c02e8 BSC_lfs_segclean
-0x40c02ec BSC_lfs_segwait
+0x40c02e0 BSC_#184
+0x40c02e4 BSC_#185
+0x40c02e8 BSC_#186
+0x40c02ec BSC_#187
0x40c02f0 BSC_stat
0x40c02f4 BSC_fstat
0x40c02f8 BSC_lstat
0x40c02fc BSC_pathconf
0x40c0300 BSC_fpathconf
-0x40c0304 BSC_getfsstat
+0x40c0304 BSC_obs_getfsstat
0x40c0308 BSC_getrlimit
0x40c030c BSC_setrlimit
0x40c0310 BSC_getdirentries
0x40c0314 BSC_mmap
-0x40c0318 BSC___syscall
+0x40c0318 BSC_#198
0x40c031c BSC_lseek
0x40c0320 BSC_truncate
0x40c0324 BSC_ftruncate
0x40c0354 BSC_#213
0x40c0358 BSC_#214
0x40c035c BSC_#215
-0x40c0360 BSC_mkcomplex
-0x40c0364 BSC_statv
-0x40c0368 BSC_lstatv
-0x40c036c BSC_fstatv
+0x40c0360 BSC_#216
+0x40c0364 BSC_#217
+0x40c0368 BSC_#218
+0x40c036c BSC_#219
0x40c0370 BSC_getattrlist
0x40c0374 BSC_setattrlist
0x40c0378 BSC_getdirentriesattr
0x40c037c BSC_exchangedata
0x40c0380 BSC_checkuseraccess
0x40c0384 BSC_searchfs
-0x40c0388 BSC_#226
-0x40c038c BSC_#227
+0x40c0388 BSC_delete
+0x40c038c BSC_copyfile
0x40c0390 BSC_#228
0x40c0394 BSC_#229
0x40c0398 BSC_#230
0x40c03bc BSC_#239
0x40c03c0 BSC_#240
0x40c03c4 BSC_#241
-0x40c03c8 BSC_#242
+0x40c03c8 BSC_fsctl
0x40c03cc BSC_#243
0x40c03d0 BSC_#244
0x40c03d4 BSC_#245
0x40c049c BSC_#295
0x40c04a0 BSC_load_shared_file
0x40c04a4 BSC_reset_shared_file
-0x40c04a8 BSC_#298
+0x40c04a8 BSC_new_system_shared_regions
0x40c04ac BSC_#299
0x40c04b0 BSC_#300
0x40c04b4 BSC_#301
0x40c04cc BSC_#307
0x40c04d0 BSC_#308
0x40c04d4 BSC_#309
-0x40c04d8 BSC_#310
+0x40c04d8 BSC_getsid
0x40c04dc BSC_#311
0x40c04e0 BSC_#312
0x40c04e4 BSC_#313
0x40c050c BSC_#323
0x40c0510 BSC_mlockall
0x40c0514 BSC_munlockall
+0x40c0518 BSC_#326
+0x40c051c BSC_issetugid
+0x40c0520 BSC_pthread_kill
+0x40c0524 BSC_pthread_sigmask
+0x40c0528 BSC_sigwait
+0x40c052c BSC_#331
+0x40c0530 BSC_#332
+0x40c0534 BSC_#333
+0x40c0538 BSC_#334
+0x40c053c BSC_utrace
+0x40c0540 BSC_#336
+0x40c0544 BSC_#337
+0x40c0548 BSC_#338
+0x40c054c BSC_#339
+0x40c0550 BSC_#340
+0x40c0554 BSC_#341
+0x40c0558 BSC_#342
+0x40c055c BSC_#343
+0x40c0560 BSC_#344
+0x40c0564 BSC_#345
+0x40c0568 BSC_#346
+0x40c056c BSC_#347
+0x40c0570 BSC_#348
+0x40c0574 BSC_#349
0x50b0018 IES_action
0x50b001c IES_filter
0x50c0010 TES_action
# Makefile API), which are rules that get invoked before and after the install
# target runs. Such rules should be specified with the '::' syntax rather than
# a single colon.
+
+after_install:
+ mkdir -p "$(DSTROOT)/usr/share/man/man8"
+ install -c -m 644 sysctl.8 "$(DSTROOT)/usr/share/man/man8/sysctl.8"
# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
OTHER_GENERATED_OFILES = $(VERS_OFILE)
+AFTER_INSTALL = after_install
.Nm systat ,
and
.Nm netstat .
-The string and integer information is summaried below.
+The string and integer information is summarized below.
For a detailed description of these variable see
.Xr sysctl 3 .
The changeable column indicates whether a process with appropriate
break;
case CTL_HW:
+ useUnsignedInt = 1;
break;
case CTL_VM:
static int
show_var(int *oid, int nlen)
{
- u_char buf[BUFSIZ], *val, *p;
+ u_char buf[BUFSIZ], *val, *mval, *p;
char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
int qoid[CTL_MAXNAME+2];
int i;
+ int retval;
size_t j, len;
u_int kind;
int (*func)(int, void *) = 0;
i = sysctl(oid, nlen, 0, &j, 0, 0);
j += j; /* we want to be sure :-) */
- val = alloca(j);
+ val = mval = malloc(j);
len = j;
i = sysctl(oid, nlen, val, &len, 0, 0);
- if (i || !len)
- return (1);
+ if (i || !len) {
+ retval = 1;
+ goto RETURN;
+ }
if (bflag) {
fwrite(val, 1, len, stdout);
- return (0);
+ retval = 0;
+ goto RETURN;
}
qoid[1] = 4;
if (!nflag)
printf("%s: ", name);
printf("%s", p);
- return (0);
+ retval = 0;
+ goto RETURN;
case 'I':
if (!nflag)
len -= sizeof (int);
p += sizeof (int);
}
- return (0);
+ retval = 0;
+ goto RETURN;
case 'L':
if (!nflag)
len -= sizeof (long);
p += sizeof (long);
}
- return (0);
+ retval = 0;
+ goto RETURN;
case 'P':
if (!nflag)
printf("%s: ", name);
printf("%p", *(void **)p);
- return (0);
+ retval = 0;
+ goto RETURN;
case 'T':
case 'S':
if (func) {
if (!nflag)
printf("%s: ", name);
- return ((*func)(len, p));
+ retval = (*func)(len, p);
+ goto RETURN;
}
/* FALL THROUGH */
default:
- if (!Aflag)
- return (1);
+ if (!Aflag) {
+ retval = 1;
+ goto RETURN;
+ }
if (!nflag)
printf("%s: ", name);
printf("Format:%s Length:%ld Dump:0x", fmt, len);
printf("...");
break;
}
- return (0);
+ retval = 0;
+ goto RETURN;
}
- return (1);
+
+ retval = 1;
+ RETURN:
+ free(mval);
+ return (retval);
}
static int
NEXTSTEP_INSTALLDIR = /usr/bin
WINDOWS_INSTALLDIR = /Library/Executables
PDO_UNIX_INSTALLDIR = /usr/bin
-LIBS =
+LIBS = -lcurses
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
#include <mach/vm_map.h>
#include <mach/vm_types.h>
#include <mach/vm_prot.h>
+#include <mach/shared_memory_server.h>
#include <device/device_types.h>
#include <CoreFoundation/CoreFoundation.h>
#include <libc.h>
#include <termios.h>
-#include <bsd/curses.h>
+#include <curses.h>
+#include <sys/ioctl.h>
/* Number of lines of header information on the standard screen */
#define HEADER_LINES 8
int total_threads;
unsigned long long total_fw_private;
-struct termios tmode, omode;
char bytesread[128];
host_cpu_load_info_data_t lastcounters, curcounters, startcounters;
struct object_info *of_free_list = 0;
-#define FW_CODE_BEG_ADDR 0x70000000
-#define FW_DATA_BEG_ADDR 0x80000000
-#define FW_DATA_END_ADDR 0x90000000
-
/*
* Translate thread state to a number in an ordered scale.
* When collapsing all the threads' states to one for the
&count, &object_name))
break;
- if (address >= FW_CODE_BEG_ADDR && address < FW_DATA_END_ADDR) {
+ if (address >= GLOBAL_SHARED_TEXT_SEGMENT && address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) {
*fw_private += info.private_pages_resident * vm_page_size;
}
}
if (split)
- *vsize -= (FW_DATA_END_ADDR - FW_CODE_BEG_ADDR);
+ *vsize -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
}
void
pmem_fw_resident(unsigned int *num_fw, unsigned long long *vsize, unsigned int *code_size, unsigned int *data_size, unsigned int *linkedit_size)
-{ vm_address_t address = FW_CODE_BEG_ADDR;
+{ vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT;
kern_return_t err = 0;
int state = 0;
*data_size = 0;
*linkedit_size = 0;
- while (address < FW_DATA_END_ADDR) {
+ while (address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) {
vm_region_submap_info_data_64_t s_info;
mach_msg_type_number_t count;
vm_size_t size;
if (err = vm_region_recurse_64(mach_task_self(), &address, &size, &nesting_depth, (vm_region_info_t)&s_info, &count))
break;
- if (address >= FW_DATA_END_ADDR)
+ if (address >= (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE))
break;
- if (address < FW_DATA_BEG_ADDR) {
+ if (address < GLOBAL_SHARED_DATA_SEGMENT) {
if (s_info.share_mode == SM_SHARED || s_info.share_mode == SM_COW) {
if (s_info.max_protection & VM_PROT_EXECUTE) {
move(LINES - 1, 0);
refresh();
endwin();
-
- tcsetattr(0, TCSANOW, &omode);
}
exit(0);
}
void quit(status) /* exit under duress */
int status;
{
- if (!oneshot) {
+ if (!oneshot)
endwin();
- tcsetattr(0, TCSANOW, &omode);
- }
exit(status);
}
/* initializes curses and screen (last) */
if (!oneshot) {
- if (tcgetattr(0, &tmode) < 0) {
- printf("can't get terminal attributes\n");
- exit(1);
- }
- omode = tmode;
-
- tmode.c_lflag &= ~ICANON;
- tmode.c_cc[VMIN] = 0;
- tmode.c_cc[VTIME] = (delay * 10);
-
- if (tcsetattr(0, TCSANOW, &tmode) < 0) {
- printf("can't set terminal attributes\n");
- exit(1);
- }
initscr();
- refresh();
+ cbreak();
+ timeout(delay * 1000);
+ noecho();
erase();
clear();
refresh();
int n;
if (newLINES) {
+ newLINES = 0;
if (!oneshot) {
- initscr();
- erase();
- clear();
- refresh();
+ struct winsize size;
+
+ if (ioctl(1, TIOCGWINSZ, &size) != -1) {
+ resizeterm(size.ws_row, size.ws_col);
+ erase();
+ clear();
+ }
}
n = LINES - Header_lines;
topn = n;
}
}
- newLINES = 0;
}
(void)screen_update();
if (!oneshot) {
+ int c;
- if ((n = read(0, &bytesread, 128)) > 0) {
- int i;
-
- for (i = 0; i < n; i++)
- if (bytesread[i] == 'q')
- leave();
- }
+ if ((c = getch()) != ERR && (char)c == 'q')
+ leave();
} else
sleep(delay);
}
(CFMutableDictionaryRef *) &properties,
kCFAllocatorDefault,
kNilOptions);
+ if (properties) {
- /* Obtain the statistics from the drive properties */
- statistics = (CFDictionaryRef) CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey));
+ /* Obtain the statistics from the drive properties */
+ statistics = (CFDictionaryRef) CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey));
- if (statistics) {
+ if (statistics) {
/* Obtain the number of bytes read from the drive statistics */
number = (CFNumberRef) CFDictionaryGetValue (statistics,
CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey));
status = CFNumberGetValue(number, kCFNumberSInt64Type, &value);
totalWriteBytes += value;
}
- }
- /* Release resources */
+ }
+ /* Release resources */
- CFRelease(properties); properties = 0;
+ CFRelease(properties); properties = 0;
+ }
IOObjectRelease(drive); drive = 0;
}
IOIteratorReset(drivelist);
# Makefile API), which are rules that get invoked before and after the install
# target runs. Such rules should be specified with the '::' syntax rather than
# a single colon.
+
+after_install:
+ mkdir -p "$(DSTROOT)/usr/share/man/man8"
+ install -c -m 644 update.8 "$(DSTROOT)/usr/share/man/man8/update.8"
# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
OTHER_GENERATED_OFILES = $(VERS_OFILE)
+AFTER_INSTALL = after_install
CFILES = vm_stat.c
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\
- h.template
+ h.template vm_stat.1
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
# owned by the top-level Makefile API and no context has been set up for where
# derived files should go.
#
+after_install:
+ install -d $(DSTROOT)/usr/share/man/man1
+ install -c -m 444 vm_stat.1 $(DSTROOT)/usr/share/man/man1
--- /dev/null
+.\" Copyright (c) 1997, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd August 13, 1997
+.Dt VM_STAT 1
+.Os Mac OS X
+.Sh NAME
+.Nm vm_stat
+.Nd show Mach virtual memory statistics
+.Sh SYNOPSIS
+.Nm vm_stat
+.Op Ar interval
+.Sh DESCRIPTION
+.Nm vm_stat
+displays Mach virtual memory statistics. If the optional
+.Ar interval
+is specified, then
+.Nm vm_stat
+will display the statistics every
+.Ar interval
+seconds. In this case, each line of output displays the change in
+each statistic (an
+.Ar interval
+count of 1 displays the values per second). However, the first line
+of output following each banner displays the system-wide totals for
+each statistic. The following values are displayed:
+.Bl -tag -width indent -compact
+.It Pages free
+the total number of free pages in the system.
+.It Pages active
+the total number of pages currently in use and pageable.
+.It Pages inactive
+the total number of pages on the inactive list.
+.It Pages wired down
+the total number of pages wired down. That is, pages that cannot be
+paged out.
+.It Translation faults
+the number of times the "vm_fault" routine has been called.
+.It Pages copy-on-write
+the number of faults that caused a page to be
+copied (generally caused by copy-on-write faults).
+.It Pages zero filled
+the total number of pages that have been zero-filled on demand.
+.It Pages reactivated
+the total number of pages that have been moved from the inactive list
+to the active list (reactivated).
+.It Pageins
+the number of requests for pages from a pager (such as the inode pager).
+.It Pageouts
+the number of pages that have been paged out.
+.Pp
+If
+.Ar interval
+is not specified, then
+.Nm vm_stat
+displays all accumulated statistics along with the page size and the
+object cache performance.
+
+
+.Sh SEE ALSO
+.Xr vm_statistics 2
# ln -s ${TZDIR}/${LOCALTIME} ${DSTROOT}/etc/localtime
#since we are not doing native builds ... hack hack hack
+
+ZONE_FILES = africa antarctica asia australasia europe northamerica southamerica pacificnew etcetera factory backward systemv solar87 solar88 solar89
+
after_install::
-mkdir -p ${DSTROOT}/usr/share
-rm -rf ${DSTROOT}/usr/share/zoneinfo
- cp -r HACK ${DSTROOT}/usr/share/zoneinfo
+ mkdir -p ${DSTROOT}/usr/share/zoneinfo
+ for tz in $(ZONE_FILES); do \
+ zic -L /dev/null -d ${DSTROOT}/usr/share/zoneinfo -y datfiles/yearistype.sh datfiles/$${tz}; \
+ done
chmod -R og-w ${DSTROOT}/usr/share/zoneinfo
-mkdir -p ${DSTROOT}/private/etc
-rm -f ${DSTROOT}/private/etc/localtime
-# $OpenBSD: africa,v 1.4 1997/01/14 04:36:47 millert Exp $
-# @(#)africa 7.16
+# @(#)africa 7.34
+
+# $FreeBSD: src/share/zoneinfo/africa,v 1.12 2000/10/25 19:36:48 wollman Exp $
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-03-22):
#
# A good source for time zone historical data outside the U.S. is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# I found in the UCLA library.
#
# A reliable and entertaining source about time zones is
-# Derek Howse, Greenwich time and the discovery of the longitude,
-# Oxford University Press (1980).
-#
-# I added so many Zone names that the old, mostly flat name space was unwieldy.
-# So I renamed the Zones to have the form AREA/LOCATION, where
-# AREA is the name of a continent or ocean, and
-# LOCATION is the name of a specific location within that region.
-# For example, the old zone name `Egypt' is now `Africa/Cairo'.
-#
-# Here are the general rules I used for choosing location names,
-# in decreasing order of importance:
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
#
-# Use only valid Posix file names. Use only Ascii letters, digits, `.',
-# `-' and `_'. Do not exceed 14 characters or start with `-'.
-# E.g. prefer `Brunei' to `Bandar_Seri_Begawan'.
-# Include at least one location per time zone rule set per country.
-# One such location is enough.
-# If all the clocks in a country's region have agreed since 1970,
-# don't bother to include more than one location
-# even if subregions' clocks disagreed before 1970.
-# Otherwise these tables would become annoyingly large.
-# If a name is ambiguous, use a less ambiguous alternative;
-# e.g. many cities are named San Jose and Georgetown, so
-# prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'.
-# Keep locations compact. Use cities or small islands, not countries
-# or regions, so that any future time zone changes do not split
-# locations into different time zones. E.g. prefer `Paris'
-# to `France', since France has had multiple time zones.
-# Use traditional English spelling, e.g. prefer `Rome' to `Roma', and
-# prefer `Athens' to the true name (which uses Greek letters).
-# The Posix file name restrictions encourage this rule.
-# Use the most populous among locations in a country's time zone,
-# e.g. prefer `Shanghai' to `Beijing'. Among locations with
-# similar populations, pick the best-known location,
-# e.g. prefer `Rome' to `Milan'.
-# Use the singular form, e.g. prefer `Canary' to `Canaries'.
-# Omit common suffixes like `_Islands' and `_City', unless that
-# would lead to ambiguity. E.g. prefer `Cayman' to
-# `Cayman_Islands' and `Guatemala' to `Guatemala_City',
-# but prefer `Mexico_City' to `Mexico' because the country
-# of Mexico has several time zones.
-# Use `_' to represent a space.
-# Omit `.' from abbreviations in names, e.g. prefer `St_Helena'
-# to `St._Helena'.
+# Previous editions of this database used WAT, CAT, SAT, and EAT
+# for +0:00 through +3:00, respectively,
+# but Mark R V Murray <markm@grondar.za> reports that
+# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
+# `CAT' is commonly used for +2:00 in countries north of South Africa, and
+# `WAT' is probably the best name for +1:00, as the common phrase for
+# the area that includes Nigeria is ``West Africa''.
+# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
#
-# For time zone abbreviations like `EST' I used the following rules,
-# in decreasing order of importance:
+# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
+# I'd guess that this was because people needed _some_ name for -1:00,
+# and at the time, far west Africa was the only major land area in -1:00.
+# This usage is now obsolete, as the last use of -1:00 on the African
+# mainland seems to have been 1976 in Western Sahara.
#
-# Use abbreviations that consist of 3 or more upper-case Ascii letters,
-# except use "___" for locations while uninhabited.
-# Posix.1 requires at least 3 characters, and the restriction to
-# upper-case Ascii letters follows most traditions.
-# Previous editions of this database also used characters like
-# ' ' and '?', but these characters have a special meaning to
-# the shell and cause commands like
-# set `date`
-# to have unexpected effects. In theory, the character set could
-# be !%./@A-Z^_a-z{}, but these tables use only upper-case
-# Ascii letters (and "___").
-# Use abbreviations that are in common use among English-speakers,
-# e.g. `EST' for Eastern Standard Time in North America.
-# We assume that applications translate them to other languages
-# as part of the normal localization process; for example,
-# a French application might translate `EST' to `HNE'.
-# For zones whose times are taken from a city's longitude, use the
-# traditional xMT notation, e.g. `PMT' for Paris Mean Time.
-# The only name like this in current use is `GMT'.
-# If there is no common English abbreviation, abbreviate the English
-# translation of the usual phrase used by native speakers.
-# If this is not available or is a phrase mentioning the country
-# (e.g. ``Cape Verde Time''), then:
+# To summarize, the following abbreviations seem to have some currency:
+# -1:00 WAT West Africa Time (no longer used)
+# 0:00 GMT Greenwich Mean Time
+# 2:00 CAT Central Africa Time
+# 2:00 SAST South Africa Standard Time
+# and Murray suggests the following abbreviation:
+# 1:00 WAT West Africa Time
+# I realize that this leads to `WAT' being used for both -1:00 and 1:00
+# for times before 1976, but this is the best I can think of
+# until we get more information.
#
-# When a country has a single or principal time zone region,
-# append `T' to the country's ISO code, e.g. `CVT' for
-# Cape Verde Time. For summer time append `ST';
-# for double summer time append `DST'; etc.
-# When a country has multiple time zones, take the first three
-# letters of an English place name identifying each zone
-# and then append `T', `ST', etc. as before;
-# e.g. `MOSST' for MOScow Summer Time.
-#
-#
-# For Africa I invented the following time zone abbreviations.
-# LMT Local Mean Time
-# -1:00 AAT Atlantic Africa Time (no longer used)
-# 0:00 WAT West Africa Time
-# 1:00 CAT Central Africa Time
-# 2:00 SAT South Africa Time
+# I invented the following abbreviations; corrections are welcome!
+# 2:00 WAST West Africa Summer Time
+# 2:30 BEAT British East Africa Time (no longer used)
+# 2:45 BEAUT British East Africa Unified Time (no longer used)
+# 3:00 CAST Central Africa Summer Time (no longer used)
+# 3:00 SAST South Africa Summer Time (no longer used)
# 3:00 EAT East Africa Time
-# The final `T' is replaced by `ST' for summer time, e.g. `SAST'.
-# BEAT is British East Africa Time, which was 2:30 before 1948 and 2:45 after.
-
+# 4:00 EAST East Africa Summer Time (no longer used)
# Algeria
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Luanda 0:52:56 - LMT 1892
0:52:04 - LMT 1911 May 26 # Luanda Mean Time?
- 1:00 - CAT
-
-# Bassas da India
-# uninhabited
+ 1:00 - WAT
# Benin
# Whitman says they switched to 1:00 in 1946, not 1934; go with Shanks.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Porto-Novo 0:10:28 - LMT 1912
- 0:00 - WAT 1934 Feb 26
- 1:00 - CAT
+ 0:00 - GMT 1934 Feb 26
+ 1:00 - WAT
# Botswana
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Gaborone 1:43:40 - LMT 1885
- 2:00 - SAT 1943 Sep 19 2:00
- 2:00 1:00 SAST 1944 Mar 19 2:00
- 2:00 - SAT
+ 2:00 - CAT 1943 Sep 19 2:00
+ 2:00 1:00 CAST 1944 Mar 19 2:00
+ 2:00 - CAT
# Burkina Faso
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Ouagadougou -0:06:04 - LMT 1912
- 0:00 - WAT
+ 0:00 - GMT
# Burundi
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Bujumbura 1:57:28 - LMT 1890
- 2:00 - SAT
+ 2:00 - CAT
# Cameroon
# Whitman says they switched to 1:00 in 1920; go with Shanks.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Douala 0:38:48 - LMT 1912
- 1:00 - CAT
+ 1:00 - WAT
# Cape Verde
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Central African Republic
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Bangui 1:14:20 - LMT 1912
- 1:00 - CAT
+ 1:00 - WAT
# Chad
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Ndjamena 1:00:12 - LMT 1912
- 1:00 - CAT 1979 Oct 14
- 1:00 1:00 CAST 1980 Mar 8
- 1:00 - CAT
+ 1:00 - WAT 1979 Oct 14
+ 1:00 1:00 WAST 1980 Mar 8
+ 1:00 - WAT
# Comoros
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Indian/Comoro 2:53:04 - LMT 1911 Jul # Moroni, Gran Comoro
3:00 - EAT
-# Congo
+# Democratic Republic of Congo
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Africa/Kinshasa 1:01:12 - LMT 1897 Nov 9
+ 1:00 - WAT
+Zone Africa/Lubumbashi 1:49:52 - LMT 1897 Nov 9
+ 2:00 - CAT
+
+# Republic of the Congo
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Brazzaville 1:01:08 - LMT 1912
- 1:00 - CAT
+ 1:00 - WAT
# Cote D'Ivoire
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Abidjan -0:16:08 - LMT 1912
- 0:00 - WAT
+ 0:00 - GMT
# Djibouti
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Egypt
-# From Bob Devine (1988-01-28):
-# Egypt: DST from first day of May to first of October (ending may
-# also be on Sept 30th not 31st -- you might want to ask one of the
-# soc.* groups, you might hit someone who could ask an embassy).
-# DST since 1960 except for 1981-82.
-
-# From U. S. Naval Observatory (1989-01-19):
-# EGYPT 2 H AHEAD OF UTC
-# EGYPT 3 H AHEAD OF UTC MAY 17 - SEP 30 (AFTER
-# EGYPT RAMADAN)
-
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Egypt 1940 only - Jul 15 0:00 1:00 S
Rule Egypt 1940 only - Oct 1 0:00 0 -
Rule Egypt 1958 only - May 1 0:00 1:00 S
Rule Egypt 1959 1981 - May 1 1:00 1:00 S
Rule Egypt 1959 1965 - Sep 30 3:00 0 -
-Rule Egypt 1966 1990 - Oct 1 3:00 0 -
+Rule Egypt 1966 1994 - Oct 1 3:00 0 -
Rule Egypt 1982 only - Jul 25 1:00 1:00 S
Rule Egypt 1983 only - Jul 12 1:00 1:00 S
Rule Egypt 1984 1988 - May 1 1:00 1:00 S
Rule Egypt 1989 only - May 6 1:00 1:00 S
-Rule Egypt 1990 only - May 1 1:00 1:00 S
-Rule Egypt 1991 1994 - May 1 0:00 1:00 S
-Rule Egypt 1991 1994 - Oct 1 0:00 0 -
-Rule Egypt 1995 max - Apr lastFri 0:00 1:00 S
-Rule Egypt 1995 max - Sep lastFri 0:00 0 -
+Rule Egypt 1990 1994 - May 1 1:00 1:00 S
+# IATA (after 1990) says transitions are at 0:00.
+# Go with IATA starting in 1995, except correct 1995 entry from 09-30 to 09-29.
+Rule Egypt 1995 max - Apr lastFri 0:00s 1:00 S
+Rule Egypt 1995 max - Sep lastThu 23:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Cairo 2:05:00 - LMT 1900 Oct
# Equatorial Guinea
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Malabo 0:35:08 - LMT 1912
- 0:00 - WAT 1963 Dec 15
- 1:00 - CAT
+ 0:00 - GMT 1963 Dec 15
+ 1:00 - WAT
# Eritrea
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Asmera 2:35:32 - LMT 1870
2:35:32 - AMT 1890 # Asmera Mean Time
- 2:35:20 - AAMT 1936 May 5 # Addis Ababa MT?
+ 2:35:20 - ADMT 1936 May 5 # Adis Dera MT
3:00 - EAT
# Ethiopia
+# From Paul Eggert (1997-10-05):
+# Shanks writes that Ethiopia had six narrowly-spaced time zones between
+# 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
+# We'll guess that 38E50 is for Adis Dera.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Addis_Ababa 2:34:48 - LMT 1870
- 2:35:20 - AAMT 1936 May 5 # Addis Ababa MT?
+ 2:35:20 - ADMT 1936 May 5 # Adis Dera MT
3:00 - EAT
-# Europa Island
-# uninhabited
-
# Gabon
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Libreville 0:37:48 - LMT 1912
- 1:00 - CAT
+ 1:00 - WAT
# Gambia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Banjul -1:06:36 - LMT 1912
-1:06:36 - BMT 1935 # Banjul Mean Time
- -1:00 - AAT 1964
- 0:00 - WAT
+ -1:00 - WAT 1964
+ 0:00 - GMT
# Ghana
-# From Paul Eggert <eggert@twinsun.com> (1996-09-03):
-# WATST is my invention for ``West Africa one-Third Summer Time''.
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# Whitman says DST was observed from 1931 to ``the present''; go with Shanks.
-Rule Ghana 1936 1942 - Sep 1 0:00 0:20 WATST
-Rule Ghana 1936 1942 - Dec 31 0:00 0 WAT
+Rule Ghana 1936 1942 - Sep 1 0:00 0:20 GHST
+Rule Ghana 1936 1942 - Dec 31 0:00 0 GMT
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Accra -0:00:52 - LMT 1918
0:00 Ghana %s
-# Glorioso Is
-# uninhabited
-
# Guinea
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Conakry -0:54:52 - LMT 1912
- 0:00 - WAT 1934 Feb 26
- 1:00 - CAT 1960
- 0:00 - WAT
+ 0:00 - GMT 1934 Feb 26
+ -1:00 - WAT 1960
+ 0:00 - GMT
# Guinea-Bissau
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Bissau -1:02:20 - LMT 1911 May 26
- 1:00 - CAT 1975
- 0:00 - WAT
-
-# Juan de Nova
-# uninhabited
+ -1:00 - WAT 1975
+ 0:00 - GMT
# Kenya
-# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
-# Shanks says the transition to 2:45 was in 1940, but it must have been 1948.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Nairobi 2:27:16 - LMT 1928 Jul
3:00 - EAT 1930
- 2:30 - BEAT 1948
- 2:45 - BEAT 1960
+ 2:30 - BEAT 1940
+ 2:45 - BEAUT 1960
3:00 - EAT
# Lesotho
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Maseru 1:50:00 - LMT 1903 Mar
- 2:00 - SAT 1943 Sep 19 2:00
+ 2:00 - SAST 1943 Sep 19 2:00
2:00 1:00 SAST 1944 Mar 19 2:00
- 2:00 - SAT
+ 2:00 - SAST
# Liberia
# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
# In 1972 Liberia was the last country to switch
-# from a GMT offset that was not a multiple of 15 minutes.
+# from a UTC offset that was not a multiple of 15 minutes.
# Howse reports that it was in honor of their president's birthday.
# Shanks reports the date as May 1, whereas Howse reports Jan; go with Shanks.
# For Liberia before 1972, Shanks reports -0:44, whereas Howse and Whitman
# each report -0:44:30; go with the more precise figure.
-#
-# From Shanks (1991), as corrected by Whitman:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Monrovia -0:43:08 - LMT 1882
-0:43:08 - MMT 1919 Mar # Monrovia Mean Time
-0:44:30 - LRT 1972 May # Liberia Time
- 0:00 - WAT
+ 0:00 - GMT
###############################################################################
# Libya
-# From Bob Devine (January 28 1988):
-# Libya: Since 1982 April 1st to September 30th (?)
-
-# From U. S. Naval Observatory (1989-01-19):
-# LIBYAN ARAB 1 H AHEAD OF UTC JAMAHIRIYA/LIBYA
-# LIBYAN ARAB 2 H AHEAD OF UTC APR 1 - SEP 30 JAMAHIRIYA/LIBYA
-
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Libya 1951 only - Oct 14 2:00 1:00 S
Rule Libya 1952 only - Jan 1 0:00 0 -
Rule Libya 1986 only - Oct 3 0:00 0 -
Rule Libya 1987 1989 - Apr 1 0:00 1:00 S
Rule Libya 1987 1990 - Oct 1 0:00 0 -
-Rule Libya 1990 only - May 4 0:00 1:00 S
-Rule Libya 1996 max - Mar 30 2:00s 1:00 S
-Rule Libya 1996 max - Sep 30 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Tripoli 0:52:44 - LMT 1920
1:00 Libya CE%sT 1959
2:00 - EET 1982
- 1:00 Libya CE%sT 1991
- 2:00 - EET 1996 Mar 30 3:00
- 1:00 Libya CE%sT
+ 1:00 Libya CE%sT 1990 May 4
+# The following entries are all from Shanks;
+# the IATA SSIM data contain some obvious errors.
+ 2:00 - EET 1996 Sep 30
+ 1:00 - CET 1997 Apr 4
+ 1:00 1:00 CEST 1997 Oct 4
+ 2:00 - EET
# Madagascar
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Malawi
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Blantyre 2:20:00 - LMT 1903 Mar
- 2:00 - SAT
+ 2:00 - CAT
# Mali
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Bamako -0:32:00 - LMT 1912
- 0:00 - WAT 1934 Feb 26
- -1:00 - AAT 1960 Jun 20
- 0:00 - WAT
+ 0:00 - GMT 1934 Feb 26
+ -1:00 - WAT 1960 Jun 20
+ 0:00 - GMT
# no longer different from Bamako, but too famous to omit
Zone Africa/Timbuktu -0:12:04 - LMT 1912
- 0:00 - WAT
+ 0:00 - GMT
# Mauritania
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Nouakchott -1:03:48 - LMT 1912
- 0:00 - WAT 1934 Feb 26
- -1:00 - AAT 1960 Jun 20
- 0:00 - WAT
+ 0:00 - GMT 1934 Feb 26
+ -1:00 - WAT 1960 Nov 28
+ 0:00 - GMT
# Mauritius
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
3:00 - EAT
# Morocco
+# See the `europe' file for Spanish Morocco (Africa/Ceuta).
# RULE NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Morocco 1939 only - Sep 12 0:00 1:00 S
Rule Morocco 1939 only - Nov 19 0:00 0 -
0:00 - WET
# Western Sahara
Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan
- -1:00 - AAT 1976 Apr 14
+ -1:00 - WAT 1976 Apr 14
0:00 - WET
# Mozambique
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Maputo 2:10:20 - LMT 1903 Mar
- 2:00 - SAT
+ 2:00 - CAT
# Namibia
+# The 1994-04-03 transition is from Shanks.
+# Shanks reports no DST after 1998-04; go with IATA.
# RULE NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Namibia 1994 max - Sep Sun>=1 2:00 1:00 S
Rule Namibia 1995 max - Apr Sun>=1 2:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8
1:30 - SWAT 1903 Mar # SW Africa Time
- 2:00 - SAT 1942 Sep 20 2:00
+ 2:00 - SAST 1942 Sep 20 2:00
2:00 1:00 SAST 1943 Mar 21 2:00
- 2:00 Namibia SA%sT
+ 2:00 - SAST 1990 Mar 21 # independence
+ 2:00 - CAT 1994 Apr 3
+ 1:00 Namibia WA%sT
# Niger
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Africa/Niamey 0:08:28 - LMT 1912
- 1:00 - CAT 1934 Feb 26
- 0:00 - WAT 1960
- 1:00 - CAT
+Zone Africa/Niamey 0:08:28 - LMT 1912
+ -1:00 - WAT 1934 Feb 26
+ 0:00 - GMT 1960
+ 1:00 - WAT
# Nigeria
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Lagos 0:13:36 - LMT 1919 Sep
- 1:00 - CAT
+ 1:00 - WAT
# Reunion
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Indian/Reunion 3:41:52 - LMT 1911 Jun # Saint-Denis
4:00 - RET # Reunion Time
+#
+# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
+# The following information about them is taken from
+# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
+# no longer available as of 1999-08-17).
+# We have no info about their time zone histories.
+#
+# Bassas da India - uninhabited
+# Europa Island - inhabited from 1905 to 1910 by two families
+# Glorioso Is - inhabited until at least 1958
+# Juan de Nova - uninhabited
+# Tromelin - inhabited until at least 1958
# Rwanda
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Kigali 2:00:16 - LMT 1935 Jun
- 2:00 - SAT
+ 2:00 - CAT
# St Helena
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Atlantic/St_Helena -0:22:48 - LMT 1890 # Jamestown
- -0:06 - SHT 1951 # St Helena Time (?)
+ -0:22:48 - JMT 1951 # Jamestown Mean Time
0:00 - GMT
# The other parts of the St Helena territory are similar:
-# Tristan da Cunha: on GMT, says Whitman
-# Ascension: on GMT, says usno1995
-# Gough, Inaccessible, Nightingale: no information, but probably GMT
+# Tristan da Cunha: on GMT, say Whitman and the CIA
+# Ascension: on GMT, says usno1995 and the CIA
+# Gough (scientific station since 1955; sealers wintered previously):
+# on GMT, says the CIA
+# Inaccessible, Nightingale: no information, but probably GMT
# Sao Tome and Principe
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Sao_Tome 0:26:56 - LMT 1884
-0:36:32 - LMT 1912 # Lisbon Mean Time
- 0:00 - WAT
+ 0:00 - GMT
# Senegal
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Dakar -1:09:44 - LMT 1912
- -1:00 - AAT 1941 Jun
- 0:00 - WAT
+ -1:00 - WAT 1941 Jun
+ 0:00 - GMT
# Seychelles
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Sierra Leone
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks.
-Rule SL 1935 1942 - Jun 1 0:00 1:00 S
-Rule SL 1935 1942 - Oct 1 0:00 0 -
-Rule SL 1957 1962 - Jun 1 0:00 1:00 S
-Rule SL 1957 1962 - Sep 1 0:00 0 -
+Rule SL 1935 1942 - Jun 1 0:00 0:40 SLST
+Rule SL 1935 1942 - Oct 1 0:00 0 WAT
+Rule SL 1957 1962 - Jun 1 0:00 1:00 SLST
+Rule SL 1957 1962 - Sep 1 0:00 0 GMT
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Freetown -0:53:00 - LMT 1882
-0:53:00 - FMT 1913 Jun # Freetown Mean Time
- -1:00 SL AA%sT 1957
- 0:00 SL WA%sT
+ -1:00 SL %s 1957
+ 0:00 SL %s
# Somalia
-# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
-# Shanks omits the 1948 transition to 2:45; this is probably a typo.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Mogadishu 3:01:28 - LMT 1893 Nov
3:00 - EAT 1931
- 2:30 - BEAT 1948
- 2:45 - BEAT 1957 # not in Shanks
+ 2:30 - BEAT 1957
3:00 - EAT
# South Africa
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule SA 1942 1943 - Sep Sun>=15 2:00 1:00 S
+Rule SA 1942 1943 - Sep Sun>=15 2:00 1:00 -
Rule SA 1943 1944 - Mar Sun>=15 2:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8
- 1:30 - SAT 1903 Mar
- 2:00 SA SA%sT
-# Prince Edward Is
+ 1:30 - SAST 1903 Mar
+ 2:00 SA SAST
+# Marion and Prince Edward Is
+# scientific station since 1947
# no information
# Sudan
-# From Michael Ross <mross@antigone.com> (1995-11-15):
-# Sudan no longer observes any form of daylight time change.
-# I verified this today by telephone with the Sudan Mission to the
-# United Nations: 212-573-6033
+#
+# From <a href="http://www.sunanews.net/sn13jane.html">
+# Sudan News Agency (2000-01-13)
+# </a>, also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
+# Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
+# Saturday.... This was announced Thursday by Caretaker State Minister for
+# Manpower Abdul-Rahman Nur-Eddin.
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Sudan 1970 only - May 1 0:00 1:00 S
Rule Sudan 1970 1985 - Oct 15 0:00 0 -
Rule Sudan 1972 1985 - Apr lastSun 0:00 1:00 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Khartoum 2:10:08 - LMT 1931
- 2:00 Sudan EE%sT
+ 2:00 Sudan CA%sT 2000 Jan 15 12:00
+ 3:00 - EAT
# Swaziland
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Mbabane 2:04:24 - LMT 1903 Mar
- 2:00 - SAT
+ 2:00 - SAST
# Tanzania
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Dar_es_Salaam 2:37:08 - LMT 1931
3:00 - EAT 1948
- 2:45 - BEAT 1961
+ 2:45 - BEAUT 1961
3:00 - EAT
# Togo
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Lome 0:04:52 - LMT 1893
- 0:00 - WAT
-
-# Tromelin
-# uninhabited
+ 0:00 - GMT
# Tunisia
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Zone Africa/Kampala 2:09:40 - LMT 1928 Jul
3:00 - EAT 1930
2:30 - BEAT 1948
- 2:45 - BEAT 1957
+ 2:45 - BEAUT 1957
3:00 - EAT
-# Zaire
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Africa/Kinshasa 1:01:12 - LMT 1897 Nov 9
- 1:00 - CAT
-Zone Africa/Lubumbashi 1:49:52 - LMT 1897 Nov 9
- 2:00 - SAT
-
# Zambia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Lusaka 1:53:08 - LMT 1903 Mar
- 2:00 - SAT
+ 2:00 - CAT
# Zimbabwe
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Harare 2:04:12 - LMT 1903 Mar
- 2:00 - SAT
+ 2:00 - CAT
-# $OpenBSD: antarctica,v 1.3 1997/01/14 04:36:48 millert Exp $
-# @(#)antarctica 7.5
+# @(#)antarctica 7.21
-# From Paul Eggert (1996-09-03):
-# To keep things manageable, we list only locations occupied year-round;
-# see <URL:http://earth.agu.org/amen/nations.html> (1996-05-24).
+# From Paul Eggert (1999-11-15):
+# To keep things manageable, we list only locations occupied year-round; see
+# <a href="http://www.comnap.aq/comnap/comnap.nsf/P/Stations/">
+# COMNAP - Stations and Bases
+# </a>
+# and
+# <a href="http://www.spri.cam.ac.uk/bob/periant.htm">
+# Summary of the Peri-Antarctic Islands (1998-07-23)
+# </a>
+# for information.
# Unless otherwise specified, we have no time zone information.
#
+# Except for the French entries,
# I made up all time zone abbreviations mentioned here; corrections welcome!
-# FORMAT is `___' and GMTOFF is 0 for locations while uninhabited.
+# FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited.
+
+# These rules are stolen from the `europe' file.
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule RussAQ 1981 1984 - Apr 1 0:00 1:00 S
+Rule RussAQ 1981 1983 - Oct 1 0:00 0 -
+Rule RussAQ 1984 1991 - Sep lastSun 2:00s 0 -
+Rule RussAQ 1985 1991 - Mar lastSun 2:00s 1:00 S
+Rule RussAQ 1992 only - Mar lastSat 23:00 1:00 S
+Rule RussAQ 1992 only - Sep lastSat 23:00 0 -
+Rule RussAQ 1993 max - Mar lastSun 2:00s 1:00 S
+Rule RussAQ 1993 1995 - Sep lastSun 2:00s 0 -
+Rule RussAQ 1996 max - Oct lastSun 2:00s 0 -
# These rules are stolen from the `southamerica' file.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule ArgAQ 1974 only - May 1 0:00 0 -
Rule ArgAQ 1974 1976 - Oct Sun<=7 0:00 1:00 S
Rule ArgAQ 1975 1977 - Apr Sun<=7 0:00 0 -
-Rule ChileAQ 1969 max - Oct Sun>=9 0:00 1:00 S
-Rule ChileAQ 1970 max - Mar Sun>=9 0:00 0 -
+Rule ChileAQ 1969 1997 - Oct Sun>=9 0:00 1:00 S
+Rule ChileAQ 1970 1998 - Mar Sun>=9 0:00 0 -
+Rule ChileAQ 1998 only - Sep 27 0:00 1:00 S
+Rule ChileAQ 1999 only - Apr 4 0:00 0 -
+Rule ChileAQ 1999 max - Oct Sun>=9 0:00 1:00 S
+Rule ChileAQ 2000 max - Mar Sun>=9 0:00 0 -
-# Argentina - 6 year-round bases
-# General Belgrano II
-# 5 others
+# Argentina - year-round bases
+# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
+# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
+# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
+# Marambio, Seymour I, -6414-05637, since 1969-10-29
+# Orcadas, Laurie I, -6016-04444, since 1904-02-22
+# San Martin, Debenham I, -6807-06708, since 1951-03-21
+# (except 1960-03 / 1976-03-21)
# Australia - territories
-# Heard Island, McDonald Islands
+# Heard Island, McDonald Islands (uninhabited)
+# previously sealers and scientific personnel wintered
+# <a href="http://www.dstc.qut.edu.au/DST/marg/daylight.html">
+# Margaret Turner reports
+# </a> (1999-09-30) that they're UTC+5, with no DST;
+# presumably this is when they have visitors.
#
# year-round bases
-# Casey, Bailey Peninsula, since 1969
-# Davis, Vestfold Hills, since 1957-01-13 (except 1965-01 - 1969-02)
-# Mawson, Holme Bay, since 1954-02-13
+# Casey, Bailey Peninsula, -6617+11032, since 1969
+# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
+# (except 1964-11 - 1969-02)
+# Mawson, Holme Bay, -6736+06253, since 1954-02-13
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Antarctica/Casey 0 - ___ 1969
+Zone Antarctica/Casey 0 - zzz 1969
8:00 - WST # Western (Aus) Standard Time
-#Zone Antartica/Davis unknown
-Zone Antarctica/Mawson 0 - ___ 1954 Feb 13
+Zone Antarctica/Davis 0 - zzz 1957 Jan 13
+ 7:00 - DAVT 1964 Nov # Davis Time
+ 0 - zzz 1969 Feb
+ 7:00 - DAVT
+Zone Antarctica/Mawson 0 - zzz 1954 Feb 13
6:00 - MAWT # Mawson Time
# References:
-# <URL:http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html> (1996-07-15)
-# <URL:http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html> (1996-04-19)
+# <a href="http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html">
+# Casey Weather (1998-02-26)
+# </a>
+# <a href="http://www.antdiv.gov.au/aad/exop/sfo/davis/video.html">
+# Davis Station, Antarctica (1998-02-26)
+# </a>
+# <a href="http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html">
+# Mawson Station, Antarctica (1998-02-25)
+# </a>
# Brazil - year-round base
# Ferraz, King George Island, since 1983/4
-# Chile - 4 year-round bases
+# Chile - year-round bases
+# Escudero, South Shetland Is, -621157-0585735, since 1994
+# Frei, King George Is, -6214-05848, since 1969
+# O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
+# Prat, -6230-05941
# China - year-round bases
# Great Wall, King George Island, since 1985-02-20
# Zhongshan, Larsemann Hills, Prydz Bay, since 1989-02-26
-# Finland - year-round base
-# Aboa, Queen Maud Land, since 1988
-
-# France
+# France - year-round bases
+#
+# From Antoine Leca <Antoine.Leca@Renault.FR> (1997-01-20):
+# Time data are from Nicole Pailleau at the IFRTP
+# (French Institute for Polar Research and Technology).
+# She confirms that French Southern Territories and Terre Adelie bases
+# don't observe daylight saving time, even if Terre Adelie supplies came
+# from Tasmania.
#
# French Southern Territories with year-round inhabitants
-# Amsterdam Island
-# Crozet Islands
-# Kerguelen Islands
-# St Paul Island
#
-# year-round base
-# Dumont d'Urville, Adelie Land, since IGY
+# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
+# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
+# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
+# whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
+#
+# St Paul Island - near Amsterdam, uninhabited
+# fishing stations operated variously 1819/1931
+#
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Indian/Kerguelen 0 - zzz 1950 # Port-aux-Francais
+ 5:00 - TFT # ISO code TF Time
+#
+# year-round base in the main continent
+# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
+#
+# Another base at Port-Martin, 50km east, began operation in 1947.
+# It was destroyed by fire on 1952-01-14.
+#
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Antarctica/DumontDUrville 0 - zzz 1947
+ 10:00 - PMT 1952 Jan 14 # Port-Martin Time
+ 0 - zzz 1956 Nov
+ 10:00 - DDUT # Dumont-d'Urville Time
+# Reference:
+# <a href="http://www.icair.iac.org.nz/science/reports/fr/IFRTP.html">
+# Support and Development of Polar Research and Technology (1997-02-03)
+# </a>
+
# Germany - year-round base
# Georg von Neumayer
# Japan - year-round bases
# Dome Fuji
# Syowa
+#
+# From Hideyuki Suzuki (1999-02-06):
+# In all Japanese stations, +0300 is used as the standard time. [See]
+# <a href="http://www.crl.go.jp/uk/uk201/basyo.htm">[reference in Japanese]</a>
+# and information from KAMO Hiroyasu <wd@ics.nara-wu.ac.jp>.
+#
+# Syowa station, which is the first antarctic station of Japan,
+# was established on 1957-01-29. Since Syowa station is still the main
+# station of Japan, it's appropriate for the principal location.
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Antarctica/Syowa 0 - zzz 1957 Jan 29
+ 3:00 - SYOT # Syowa Time
+# See:
+# <a href="http://www.nipr.ac.jp/english/ara01.html">
+# NIPR Antarctic Research Activities (1999-08-17)
+# </a>
# S Korea - year-round base
# King Sejong, King George Island, since 1988
# New Zealand - claims
-# Balleny Islands
-# Scott Island
+# Balleny Islands (never inhabited)
+# Scott Island (never inhabited)
#
# year-round base
# Scott, Ross Island, since 1957-01, is like Antarctica/McMurdo.
Rule NZAQ 1990 max - Mar Sun>=15 2:00s 0 S
# Norway - territories
-# Bouvet (uninhabited)
+# Bouvet (never inhabited)
#
# claims
-# Peter I Island (uninhabited)
+# Peter I Island (never inhabited)
# Poland - year-round base
-# Arctowski, King George Island, since 1977
+# Arctowski, King George Island, -620945-0582745, since 1977
# Russia - year-round bases
-# Bellingshausen, King George Island
-# Mirny
-# Molodezhnaya
-# Novolazarevskaya
-# Vostok
+# Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
+# Mirny, Davis coast, -6633+09301, since 1956-02
+# Molodezhnaya, Alasheyev Bay, year-round from 1962-02 to 1999-07-01
+# Novolazarevskaya, Queen Maud Land, -7046+01150,
+# year-round from 1960/61 to 1992
+
+# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
+# <a href="http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP">
+# From Craig Mundell (1994-12-15)</a>:
+# Vostok, which is one of the Russian stations, is set on the same
+# time as Moscow, Russia.
+#
+# From Lee Hotz (2001-03-08):
+# I queried the folks at Columbia who spent the summer at Vostok and this is
+# what they had to say about time there:
+# ``in the US Camp (East Camp) we have been on New Zealand (McMurdo)
+# time, which is 12 hours ahead of GMT. The Russian Station Vostok was
+# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead
+# of GMT). This is a time zone I think two hours east of Moscow. The
+# natural time zone is in between the two: 8 hours ahead of GMT.''
+#
+Zone Antarctica/Vostok 0 - zzz 1957 Dec 16
+ 6:00 - VOST # Vostok time
# S Africa - year-round bases
# Marion Island
#
# British Antarctic Territories (BAT) claims
# South Orkney Islands
+# scientific station from 1903
+# whaling station at Signy I 1920/1926
# South Shetland Islands
#
# year-round bases
-# Halley, Coates Land, -7535-2619, since 1956-01-06
+# Bird Island, South Georgia, -5400-03803, since 1983
+# Deception Island, -6259-06034, whaling station 1912/1931,
+# scientific station 1943/1967,
+# previously sealers and a scientific expedition wintered by accident,
+# and a garrison was deployed briefly
+# Halley, Coates Land, -7535-02604, since 1956-01-06
+# Halley is on a moving ice shelf and is periodically relocated
+# so that it is never more than 10km from its nominal location.
# Rothera, Adelaide Island, -6734-6808, since 1976-12-01
# Uruguay - year round base
-# Artigas, King George Island
+# Artigas, King George Island, -621104-0585107
# USA - year-round bases
#
# Palmer used to be supplied from Argentina.
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Antarctica/Palmer 0 - ___ 1965
+Zone Antarctica/Palmer 0 - zzz 1965
-4:00 ArgAQ AR%sT 1969 Oct 5
-3:00 ArgAQ AR%sT 1982 May
-4:00 ChileAQ CL%sT
#
#
-# McMurdo, Ross Island, since 1956
+# McMurdo, Ross Island, since 1955-12
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Antarctica/McMurdo 0 - ___ 1956
+Zone Antarctica/McMurdo 0 - zzz 1956
12:00 NZAQ NZ%sT
#
-# Amundsen-Scott, South Pole, since 1957-01-23
+# Amundsen-Scott, South Pole, continuously occupied since 1956-11-20
+#
# From Paul Eggert (1996-09-03):
# Normally it wouldn't have a separate entry, since it's like the
# larger Antarctica/McMurdo since 1970, but it's too famous to omit.
# which was on GMT+12 because New Zealand was on GMT+12 all year
# at that time (1957). (Source: Siple's book 90 degrees SOUTH.)
#
-# From Susan Smith <URL:http://www.cybertours.com/whs/pole10.html>
-# (1995-11-13 16:24:56 +1300): We use the same time as McMurdo does.
+# From Susan Smith
+# http://www.cybertours.com/whs/pole10.html
+# (1995-11-13 16:24:56 +1300, no longer available):
+# We use the same time as McMurdo does.
# And they use the same time as Christchurch, NZ does....
# One last quirk about South Pole time.
# All the electric clocks are usually wrong.
-# $OpenBSD: asia,v 1.5 1997/01/14 04:36:48 millert Exp $
-# @(#)asia 7.27
+# @(#)asia 7.63
+
+# $FreeBSD: src/share/zoneinfo/asia,v 1.18 2001/04/06 16:46:52 wollman Exp $
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-03-22):
#
# A good source for time zone historical data outside the U.S. is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
-# Except where otherwise noted, it is the source for the data below.
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# I found in the UCLA library.
#
# A reliable and entertaining source about time zones is
-# Derek Howse, Greenwich time and the discovery of the longitude,
-# Oxford University Press (1980).
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
#
# I invented the abbreviations marked `*' in the following table;
# the rest are from earlier versions of this file, or from other sources.
# 5:30 IST India
# 7:00 ICT Indochina*
# 8:00 CST China
+# 9:00 CJT Central Japanese Time (1896/1937)*
# 9:00 JST Japan
# 9:00 KST Korea
# 9:30 CST (Australian) Central Standard Time
#
# See the `europe' file for Russia and Turkey in Asia.
-#
-# See the `africa' file for time zone naming and abbreviation conventions.
# From Guy Harris:
# Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
4:30 - AFT
# Armenia
-# From Paul Eggert (1996-05-04):
+# From Paul Eggert (1999-10-29):
# Shanks has Yerevan switching to 3:00 (with Russian DST) in spring 1991,
-# but usno1995 has Armenia at 4:00 (with DST), and Edgar Der-Danieliantz
-# <edd@AIC.NET> reported today that Yerevan probably won't use DST this year,
-# though it did use DST in 1995. We guess Yerevan stayed in sync with Moscow
-# between 1990 and 1995, but stopped using DST in 1996.
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Armenia 1991 1995 - Mar lastSun 2:00s 1:00 S
-Rule Armenia 1991 1995 - Sep lastSun 2:00s 0 -
+# then to 4:00 with no DST in fall 1995, then readopting Russian DST in 1997.
+# Go with Shanks, even when he disagrees with others. Edgar Der-Danieliantz
+# <edd@AIC.NET> reported (1996-05-04) that Yerevan probably wouldn't use DST
+# in 1996, though it did use DST in 1995. IATA SSIM (1991/1998) reports that
+# Armenia switched from 3:00 to 4:00 in 1998 and observed DST after 1991,
+# but started switching at 3:00s in 1998.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2
3:00 - YERT 1957 Mar # Yerevan Time
4:00 RussiaAsia YER%sT 1991 Mar 31 2:00s
3:00 1:00 YERST 1991 Sep 23 # independence
- 3:00 Armenia AM%sT 1992 Jan 19 2:00s # Armenia Time
- 4:00 Armenia AM%sT
+ 3:00 RussiaAsia AM%sT 1995 Sep 24 2:00s
+ 4:00 - AMT 1997
+ 4:00 RussiaAsia AM%sT
# Azerbaijan
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Azer 1997 max - Mar lastSun 1:00 1:00 S
+Rule Azer 1997 max - Oct lastSun 1:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Baku 3:19:24 - LMT 1924 May 2
3:00 - BAKT 1957 Mar # Baku Time
3:00 1:00 BAKST 1991 Aug 30 # independence
3:00 RussiaAsia AZ%sT 1992 Sep lastSun 2:00s
4:00 - AZT 1996 # Azerbaijan time
- 4:00 EUAsia AZ%sT
+ 4:00 EUAsia AZ%sT 1997
+ 4:00 Azer AZ%sT
# Bahrain
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Bahrain 3:22:20 - LMT 1920 # Al-Manamah
+Zone Asia/Bahrain 3:22:20 - LMT 1920 # Al Manamah
4:00 - GST 1972 Jun
3:00 - AST
# Bangladesh
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Dacca 6:01:40 - LMT 1890
+Zone Asia/Dhaka 6:01:40 - LMT 1890
5:53:20 - HMT 1941 Oct # Howrah Mean Time?
6:30 - BURT 1942 May 15 # Burma Time
5:30 - IST 1942 Sep
# Bhutan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Thimbu 5:58:36 - LMT 1947 Aug 15
+Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu
5:30 - IST 1987 Oct
6:00 - BTT # Bhutan Time
8:00 - ICT 1931 May
7:00 - ICT
-# People's Republic of China
+# China
# From Guy Harris:
# People's Republic of China. Yes, they really have only one time zone.
# note about Time magazine, though apparently _something_ happened in 1986.
# Go with Shanks for now. I made up names for the other pre-1980 time zones.
-# From Shanks (1991):
+# From Shanks:
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Shang 1940 only - Jun 3 0:00 1:00 D
Rule Shang 1940 1941 - Oct 1 0:00 0 S
Rule PRC 1986 1991 - Sep Sun>=11 0:00 0 S
Rule PRC 1987 1991 - Apr Sun>=10 0:00 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Harbin 8:26:44 - LMT 1928
+Zone Asia/Harbin 8:26:44 - LMT 1928 # or Haerbin
8:30 - HART 1932 Mar # Harbin Time
8:00 - CST 1940
9:00 - HART 1966 May
Zone Asia/Shanghai 8:05:52 - LMT 1928
8:00 Shang C%sT 1949
8:00 PRC C%sT
-Zone Asia/Chungking 7:06:20 - LMT 1928
+Zone Asia/Chungking 7:06:20 - LMT 1928 # or Chongqing
7:00 - CHUT 1980 May # Chungking Time
8:00 PRC C%sT
-Zone Asia/Urumqi 5:50:20 - LMT 1928
+Zone Asia/Urumqi 5:50:20 - LMT 1928 # or Urumchi
6:00 - URUT 1980 May # Urumqi Time
8:00 PRC C%sT
-Zone Asia/Kashgar 5:03:56 - LMT 1928
+Zone Asia/Kashgar 5:03:56 - LMT 1928 # or Kashi or Kaxgar
5:30 - KAST 1940 # Kashgar Time
5:00 - KAST 1980 May
8:00 PRC C%sT
+# Hong Kong (Xianggang)
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule HK 1946 only - Apr 20 3:30 1:00 S
+Rule HK 1946 only - Dec 1 3:30 0 -
+Rule HK 1947 only - Apr 13 3:30 1:00 S
+Rule HK 1947 only - Dec 30 3:30 0 -
+Rule HK 1948 only - May 2 3:30 1:00 S
+Rule HK 1948 1952 - Oct lastSun 3:30 0 -
+Rule HK 1949 1953 - Apr Sun>=1 3:30 1:00 S
+Rule HK 1953 only - Nov 1 3:30 0 -
+Rule HK 1954 1964 - Mar Sun>=18 3:30 1:00 S
+Rule HK 1954 only - Oct 31 3:30 0 -
+Rule HK 1955 1964 - Nov Sun>=1 3:30 0 -
+Rule HK 1965 1977 - Apr Sun>=16 3:30 1:00 S
+Rule HK 1965 1977 - Oct Sun>=16 3:30 0 -
+Rule HK 1979 1980 - May Sun>=8 3:30 1:00 S
+Rule HK 1979 1980 - Oct Sun>=16 3:30 0 -
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Asia/Hong_Kong 7:36:36 - LMT 1904 Oct 30
+ 8:00 HK HK%sT
+
###############################################################################
-# Republic of China
+# Taiwan
+
+# Shanks writes that Taiwan observed DST during 1945, when it
+# was still controlled by Japan. This is hard to believe, but we don't
+# have any other information.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Taiwan 1945 1951 - May 1 0:00 1:00 D
Zone Asia/Taipei 8:06:00 - LMT 1896
8:00 Taiwan C%sT
-###############################################################################
-# Hong Kong
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule HK 1946 only - Apr 20 3:30 1:00 S
-Rule HK 1946 only - Dec 1 3:30 0 -
-Rule HK 1947 only - Apr 13 3:30 1:00 S
-Rule HK 1947 only - Dec 30 3:30 0 -
-Rule HK 1948 only - May 2 3:30 1:00 S
-Rule HK 1948 1952 - Oct lastSun 3:30 0 -
-Rule HK 1949 1953 - Apr Sun>=1 3:30 1:00 S
-Rule HK 1953 only - Nov 1 3:30 0 -
-Rule HK 1954 1964 - Mar Sun>=18 3:30 1:00 S
-Rule HK 1954 only - Oct 31 3:30 0 -
-Rule HK 1955 1964 - Nov Sun>=1 3:30 0 -
-Rule HK 1965 1977 - Apr Sun>=16 3:30 1:00 S
-Rule HK 1965 1977 - Oct Sun>=16 3:30 0 -
-Rule HK 1979 1980 - May Sun>=8 3:30 1:00 S
-Rule HK 1979 1980 - Oct Sun>=16 3:30 0 -
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Hong_Kong 7:36:36 - LMT 1904 Oct 30
- 8:00 HK HK%sT 1997 Jul 1 # return to China
- 8:00 PRC C%sT
-
-# Macao
+# Macao (Macau, Aomen)
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Macao 1961 1962 - Mar Sun>=16 3:30 1:00 S
Rule Macao 1961 1964 - Nov Sun>=1 3:30 0 -
Rule Cyprus 1977 1980 - Apr Sun>=1 0:00 1:00 S
Rule Cyprus 1977 only - Sep 25 0:00 0 -
Rule Cyprus 1978 only - Oct 2 0:00 0 -
-Rule Cyprus 1979 max - Sep lastSun 0:00 0 -
-Rule Cyprus 1981 max - Mar lastSun 0:00 1:00 S
+Rule Cyprus 1979 1997 - Sep lastSun 0:00 0 -
+Rule Cyprus 1981 1998 - Mar lastSun 0:00 1:00 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Nicosia 2:13:28 - LMT 1921 Nov 14
- 2:00 Cyprus EE%sT
+ 2:00 Cyprus EE%sT 1998 Sep
+ 2:00 EUAsia EE%sT
+# IATA SSIM (1998-09) has Cyprus using EU rules for the first time.
+
+# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72.
+# However, for various reasons many users expect to find it under Europe.
+Link Asia/Nicosia Europe/Nicosia
# Georgia
# From Paul Eggert <eggert@twinsun.com> (1994-11-19):
3:00 RussiaAsia GE%sT 1992 # Georgia Time
3:00 E-EurAsia GE%sT 1994 Sep lastSun
4:00 E-EurAsia GE%sT 1996 Oct lastSun
- 5:00 - GET
+ 4:00 1:00 GEST 1997 Mar lastSun
+ 4:00 E-EurAsia GE%sT
+
+# East Timor
+
+# From Joao Carrascalao, brother of the former governor of East Timor, in
+# <a href="http://etan.org/et99c/december/26-31/30ETMAY.htm">
+# East Timor may be late for its millennium
+# </a> (1999-12-26/31):
+# Portugal tried to change the time forward in 1974 because the sun
+# rises too early but the suggestion raised a lot of problems with the
+# Timorese and I still don't think it would work today because it
+# conflicts with their way of life.
+
+# From Paul Eggert (2000-12-04):
+# We don't have any record of the above attempt.
+# Most likely our records are incomplete, but we have no better data.
+
+# <a href="http://www.hri.org/news/world/undh/last/00-08-16.undh.html">
+# From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
+# (2000-08-16)</a>:
+# The Cabinet of the East Timor Transition Administration decided
+# today to advance East Timor's time by one hour. The time change,
+# which will be permanent, with no seasonal adjustment, will happen at
+# midnight on Saturday, September 16.
+
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Asia/Dili 8:22:20 - LMT 1912
+ 8:00 - TPT 1942 Feb 21 23:00 # E Timor Time
+ 9:00 - JST 1945 Aug
+ 9:00 - TPT 1976 May 3
+ 8:00 - TPT 2000 Sep 17 00:00
+ 9:00 - TPT
# India
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Indonesia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Jakarta 7:07:12 - LMT 1867 Aug 10
- 7:07:12 - JMT 1924 Jan 1 0:13 # Jakarta MT
+# Shanks says the next transition was at 1924 Jan 1 0:13,
+# but this must be a typo.
+ 7:07:12 - JMT 1923 Dec 31 23:47:12 # Jakarta
7:20 - JAVT 1932 Nov # Java Time
7:30 - JAVT 1942 Mar 23
9:00 - JST 1945 Aug
9:00 - JAYT
# Iran
-# From Paul Eggert (1996-12-17), following up a suggestion by Rich Wales:
-# Ahmad Alavi <URL:http://tehran.stanford.edu/Iran_Lib/Calendar/taghveem.txt>
-# (1993-08-04) writes ``Daylight saving time in Iran starts from the first day
+# From Paul Eggert (2000-06-12), following up a suggestion by Rich Wales:
+# Ahmea Alavi in
+# <a href="http://www.persia.org/Iran_Lib/Calendar/taghveem.txt">
+# TAGHVEEM (1993-07-12)
+# </a>
+# writes ``Daylight saving time in Iran starts from the first day
# of Farvardin and ends the first day of Mehr.'' This disagrees with the SSIM:
#
# DST start DST end
# 1993 03-21 03-21 09-23 09-23
# 1994 03-21 03-21 09-22!= 09-23
# 1995 03-21 03-21 09-22!= 09-23
-# 1996 03-21!= 03-20 09-21!= 09-22
-# 1997 03-21 03-21 09-21!= 09-23
+# 1996 03-21!= 03-20 09-22 09-22
+# 1997 03-22!= 03-21 09-22!= 09-23
+# 1998 03-21 03-21 09-21!= 09-23
+# 1999 03-22!= 03-21 09-22!= 09-23
+# 2000 03-21!= 03-20 09-21!= 09-22
+# 2001 03-19!= 03-21 09-19!= 09-23
+# 2002 03-18!= 03-21 09-18!= 09-23
#
# Go with Alavi starting with 1992.
# I used Ed Reingold's cal-persia in GNU Emacs 19.34 to compute Persian dates.
4:00 Iran IR%sT 1979
3:30 Iran IR%sT
+
# Iraq
+#
+# From Jonathan Lennox <lennox@cs.columbia.edu> (2000-06-12):
+# An article in this week's Economist ("Inside the Saddam-free zone", p. 50 in
+# the U.S. edition) on the Iraqi Kurds contains a paragraph:
+# "The three northern provinces ... switched their clocks this spring and
+# are an hour ahead of Baghdad."
+#
+# But Rives McDow (2000-06-18) quotes a contact in Iraqi-Kurdistan as follows:
+# In the past, some Kurdish nationalists, as a protest to the Iraqi
+# Government, did not adhere to daylight saving time. They referred
+# to daylight saving as Saddam time. But, as of today, the time zone
+# in Iraqi-Kurdistan is on standard time with Baghdad, Iraq.
+#
+# So we'll ignore the Economist's claim.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Iraq 1982 only - May 1 0:00 1:00 D
Rule Iraq 1982 1984 - Oct 1 0:00 0 S
Rule Iraq 1985 1990 - Sep lastSun 1:00s 0 S
Rule Iraq 1986 1990 - Mar lastSun 1:00s 1:00 D
# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
+# Shanks says Iraq did not observe DST 1992/1997 or 1999 on; ignore this.
Rule Iraq 1991 max - Apr 1 3:00s 1:00 D
-Rule Iraq 1991 max - Oct 1 3:00s 0 D
+Rule Iraq 1991 max - Oct 1 3:00s 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Baghdad 2:57:40 - LMT 1890
2:57:36 - BMT 1918 # Baghdad Mean Time?
# Israel
-# From U. S. Naval Observatory (1989-01-19):
-# ISRAEL 2 H AHEAD OF UTC
-# ISRAEL 3 H AHEAD OF UTC APR 10 - SEP 3
-
-# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
+# From Ephraim Silverberg (2001-01-11):
+#
+# I coined "IST/IDT" circa 1988. Until then there were three
+# different abbreviations in use:
+#
+# JST Jerusalem Standard Time [Danny Braniss, Hebrew University]
+# IZT Israel Zonal (sic) Time [Prof. Haim Papo, Technion]
+# EEST Eastern Europe Standard Time [used by almost everyone else]
+#
+# Since timezones should be called by country and not capital cities,
+# I ruled out JST. As Israel is in Asia Minor and not Eastern Europe,
+# EEST was equally unacceptable. Since "zonal" was not compatible with
+# any other timezone abbreviation, I felt that 'IST' was the way to go
+# and, indeed, it has received almost universal acceptance in timezone
+# settings in Israeli computers.
#
-# Shanks gives the following rules for Jerusalem from 1918 through 1991.
-# After 1989 Shanks often disagrees with Silverberg; we go with Silverberg.
+# In any case, I am happy to share timezone abbreviations with India,
+# high on my favorite-country list (and not only because my wife's
+# family is from India).
-# From Shanks (1991):
+# From Shanks:
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Zion 1940 only - Jun 1 0:00 1:00 D
Rule Zion 1942 1944 - Nov 1 0:00 0 S
Rule Zion 1988 only - Apr 9 0:00 1:00 D
Rule Zion 1988 only - Sep 3 0:00 0 S
-# From Ephraim Silverberg (1996-01-02):
-#
+# From Ephraim Silverberg <ephraim@cs.huji.ac.il>
+# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17 and 2000-07-25):
+
# According to the Office of the Secretary General of the Ministry of
# Interior, there is NO set rule for Daylight-Savings/Standard time changes.
-# Each year they decide anew what havoc to wreak on the country. However,
-# there is a "supposed" set of rules which is subject to change depending
-# on the party the Minister of Interior, the size of the coalition
-# government, the phase of the moon and the direction of the wind. Hence,
-# changes may need to be made on a semi-annual basis. One thing is entrenched
-# in law, however: that there must be at least 150 days of daylight savings
-# time annually. Ever since 1993, the change to daylight savings time has
-# been from midnight Thursday night to 1 a.m. Friday morning and the change
-# back to standard time on Saturday night from midnight daylight savings time
-# to 11 p.m. standard time. 1996 is an exception to this rule where the
-# change back to standard time takes place on Sunday night instead of Saturday
-# night to avoid conflicts with the Jewish New Year.
+# One thing is entrenched in law, however: that there must be at least 150
+# days of daylight savings time annually. From 1993-1998, the change to
+# daylight savings time was on a Friday morning from midnight IST to
+# 1 a.m IDT; up until 1998, the change back to standard time was on a
+# Saturday night from midnight daylight savings time to 11 p.m. standard
+# time. 1996 is an exception to this rule where the change back to standard
+# time took place on Sunday night instead of Saturday night to avoid
+# conflicts with the Jewish New Year. In 1999, the change to
+# daylight savings time was still on a Friday morning but from
+# 2 a.m. IST to 3 a.m. IDT; furthermore, the change back to standard time
+# was also on a Friday morning from 2 a.m. IDT to 1 a.m. IST for
+# 1999 only. In the year 2000, the change to daylight savings time was
+# similar to 1999, but although the change back will be on a Friday, it
+# will take place from 1 a.m. IDT to midnight IST. Starting in 2001, all
+# changes to/from will take place at 1 a.m. old time, but now there is no
+# rule as to what day of the week it will take place in as the start date
+# (except in 2003) is the night after the Passover Seder (i.e. the eve
+# of the 16th of Nisan in the lunar Hebrew calendar) and the end date
+# (except in 2002) is three nights before Yom Kippur [Day of Atonement]
+# (the eve of the 7th of Tishrei in the lunar Hebrew calendar).
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Zion 1989 only - Apr 30 0:00 1:00 D
# The dates for 1994-1995 were obtained from Office of the Spokeswoman for the
# Ministry of Interior, Jerusalem, Israel. The spokeswoman can be reached by
-# calling the switchboard at 972-2-701411 and asking for the spokeswoman.
+# calling the office directly at 972-2-6701447 or 972-2-6701448.
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Zion 1994 only - Apr 1 0:00 1:00 D
Rule Zion 1994 only - Aug 28 0:00 0 S
Rule Zion 1995 only - Mar 31 0:00 1:00 D
Rule Zion 1995 only - Sep 3 0:00 0 S
-# The dates for 1996-1998 were also obtained from Office of the Spokeswoman
-# for the Ministry of Interior, Jerusalem, Israel. The official announcement
-# can be viewed (in Hebrew) at the following URL:
+# The dates for 1996 were determined by the Minister of Interior of the
+# time, Haim Ramon. The official announcement regarding 1996-1998
+# (with the dates for 1997-1998 no longer being relevant) can be viewed at:
+#
+# ftp://ftp.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
+#
+# The dates for 1997-1998 were altered by his successor, Rabbi Eli Suissa.
+#
+# The official announcements for the years 1997-1999 can be viewed at:
#
-# ftp://ftp.huji.ac.il/pub/misc/timezones/announcements/1996-1998.ps.gz
+# ftp://ftp.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
#
-# Caveat emptor: The dates for the years 1996-1998 were originally announced
-# on 1995-08-31, by the previous Minister of Interior. The new Minister
-# of Interior changed the dates on 1996-01-01, to take into account the
-# desires of certain portions of Israeli society (the next election is in the
-# Fall of 1996). After this (1996) year's Daylight Savings Time is over, the
-# new minister has announced that a study will be conducted as to the wishes of
-# the populace regarding the length of Daylight Savings Time and the Interior
-# Committee will meet to review the results of the study and make any necessary
-# changes to the 1997-1998 dates. Never a dull moment in the State of Israel.
+# where YYYY is the relevant year.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Zion 1996 1998 - Mar Fri>=14 0:00 1:00 D
+Rule Zion 1996 only - Mar 15 0:00 1:00 D
Rule Zion 1996 only - Sep 16 0:00 0 S
-Rule Zion 1997 1998 - Oct Sun>=14 0:00 0 S
+Rule Zion 1997 only - Mar 21 0:00 1:00 D
+Rule Zion 1997 only - Sep 14 0:00 0 S
+Rule Zion 1998 only - Mar 20 0:00 1:00 D
+Rule Zion 1998 only - Sep 6 0:00 0 S
+Rule Zion 1999 only - Apr 2 2:00 1:00 D
+Rule Zion 1999 only - Sep 3 2:00 0 S
+
+# The Knesset Interior Committee has changed the dates for 2000 for
+# the third time in just over a year and have set new dates for the
+# years 2001-2004 as well.
+#
+# The official announcement for the start date of 2000 can be viewed at:
+#
+# ftp://ftp.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
+#
+# The official announcement for the end date of 2000 and the dates
+# for the years 2001-2004 can be viewed at:
+#
+# ftp://ftp.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
+
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Zion 2000 only - Apr 14 2:00 1:00 D
+Rule Zion 2000 only - Oct 6 1:00 0 S
+Rule Zion 2001 only - Apr 9 1:00 1:00 D
+Rule Zion 2001 only - Sep 24 1:00 0 S
+Rule Zion 2002 only - Mar 29 1:00 1:00 D
+Rule Zion 2002 only - Oct 7 1:00 0 S
+Rule Zion 2003 only - Mar 28 1:00 1:00 D
+Rule Zion 2003 only - Oct 3 1:00 0 S
+Rule Zion 2004 only - Apr 7 1:00 1:00 D
+Rule Zion 2004 only - Sep 22 1:00 0 S
+
+# From Paul Eggert (2000-07-25):
+# Here are guesses for rules after 2004.
+# They are probably wrong, but they are more likely than no DST at all.
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Zion 2005 max - Apr 1 1:00 1:00 D
+Rule Zion 2005 max - Oct 1 1:00 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Jerusalem 2:20:56 - LMT 1880
# but the only locations using it were US military bases.
# We go with Shanks and omit daylight saving in those years for Asia/Tokyo.
+# From Hideyuki Suzuki (1998-11-09):
+# 'Tokyo' usually stands for the former location of Tokyo Astronomical
+# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
+# This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
+# edited by National Astronomical Observatory of Japan....
+# JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
+# The law is enacted on 1886-07-07.
+
+# From Hideyuki Suzuki (1998-11-16):
+# The ordinance No. 51 (1886) established "standard time" in Japan,
+# which stands for the time on E 135 degree.
+# In the ordinance No. 167 (1895), "standard time" was renamed to "central
+# standard time". And the same ordinance also established "western standard
+# time", which stands for the time on E 120 degree.... But "western standard
+# time" was abolished in the ordinance No. 529 (1937). In the ordinance No.
+# 167, there is no mention regarding for what place western standard time is
+# standard....
+#
+# I wrote "ordinance" above, but I don't know how to translate.
+# In Japanese it's "chokurei", which means ordinance from emperor.
+
+# Shanks claims JST in use since 1896, and that a few places (e.g. Ishigaki)
+# use +0800; go with Suzuki. Guess that all ordinances took effect on Jan 1.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Tokyo 9:19:04 - LMT 1896
+Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u
+ 9:00 - JST 1896
+ 9:00 - CJT 1938
9:00 - JST
-Zone Asia/Ishigaki 8:16:36 - LMT 1896
- 8:00 - CST
-# There is no information for Marcus.
-# Other Japanese possessions are probably like Asia/Tokyo.
+# Since 1938, all Japanese possessions have been like Asia/Tokyo.
# Jordan
+#
+# From <a href="http://star.arabia.com/990701/JO9.html">
+# Jordan Week (1999-07-01) </a> via Steffen Thorsen (1999-09-09):
+# Clocks in Jordan were forwarded one hour on Wednesday at midnight,
+# in accordance with the government's decision to implement summer time
+# all year round.
+#
+# From <a href="http://star.arabia.com/990930/JO9.html">
+# Jordan Week (1999-09-30) </a> via Steffen Thorsen (1999-11-09):
+# Winter time starts today Thursday, 30 September. Clocks will be turned back
+# by one hour. This is the latest government decision and it's final!
+# The decision was taken because of the increase in working hours in
+# government's departments from six to seven hours.
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Jordan 1973 only - Jun 6 0:00 1:00 S
-Rule Jordan 1973 1975 - Oct 1 0:00 0 -
-Rule Jordan 1974 1977 - May 1 0:00 1:00 S
-Rule Jordan 1976 only - Nov 1 0:00 0 -
-Rule Jordan 1977 only - Oct 1 0:00 0 -
-Rule Jordan 1978 only - Apr 30 0:00 1:00 S
-Rule Jordan 1978 only - Sep 30 0:00 0 -
-Rule Jordan 1985 only - Apr 1 0:00 1:00 S
-Rule Jordan 1985 only - Oct 1 0:00 0 -
-Rule Jordan 1986 1988 - Apr Fri>=1 0:00 1:00 S
-Rule Jordan 1986 1990 - Oct Fri>=1 0:00 0 -
-Rule Jordan 1989 only - May 8 0:00 1:00 S
-Rule Jordan 1990 only - Apr 27 0:00 1:00 S
-Rule Jordan 1991 only - Apr 17 0:00 1:00 S
-Rule Jordan 1991 only - Sep 27 0:00 0 -
-Rule Jordan 1992 only - Apr 10 0:00 1:00 S
-Rule Jordan 1992 1993 - Oct Fri>=1 0:00 0 -
-Rule Jordan 1993 max - Apr Fri>=1 0:00 1:00 S
-Rule Jordan 1994 only - Sep Fri>=15 0:00 0 -
-Rule Jordan 1995 max - Sep Fri>=15 0:00s 0 -
+Rule Jordan 1973 only - Jun 6 0:00 1:00 S
+Rule Jordan 1973 1975 - Oct 1 0:00 0 -
+Rule Jordan 1974 1977 - May 1 0:00 1:00 S
+Rule Jordan 1976 only - Nov 1 0:00 0 -
+Rule Jordan 1977 only - Oct 1 0:00 0 -
+Rule Jordan 1978 only - Apr 30 0:00 1:00 S
+Rule Jordan 1978 only - Sep 30 0:00 0 -
+Rule Jordan 1985 only - Apr 1 0:00 1:00 S
+Rule Jordan 1985 only - Oct 1 0:00 0 -
+Rule Jordan 1986 1988 - Apr Fri>=1 0:00 1:00 S
+Rule Jordan 1986 1990 - Oct Fri>=1 0:00 0 -
+Rule Jordan 1989 only - May 8 0:00 1:00 S
+Rule Jordan 1990 only - Apr 27 0:00 1:00 S
+Rule Jordan 1991 only - Apr 17 0:00 1:00 S
+Rule Jordan 1991 only - Sep 27 0:00 0 -
+Rule Jordan 1992 only - Apr 10 0:00 1:00 S
+Rule Jordan 1992 1993 - Oct Fri>=1 0:00 0 -
+Rule Jordan 1993 1998 - Apr Fri>=1 0:00 1:00 S
+Rule Jordan 1994 only - Sep Fri>=15 0:00 0 -
+Rule Jordan 1995 1998 - Sep Fri>=15 0:00s 0 -
+Rule Jordan 1999 only - Jul 1 0:00s 1:00 S
+Rule Jordan 1999 max - Sep lastThu 0:00s 0 -
+Rule Jordan 2000 max - Mar lastThu 0:00s 1:00 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Amman 2:23:44 - LMT 1931
2:00 Jordan EE%sT
# IATA SSIM mentions a third time zone in Kazakhstan.
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Alma-Ata 5:07:48 - LMT 1924 May 2 # or Almaty
+Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata
5:00 - ALMT 1957 Mar # Alma-Ata Time
6:00 RussiaAsia ALM%sT 1991 Mar 31 2:00s
5:00 1:00 ALMST 1991 Sep 29 2:00s
5:00 E-EurAsia AQT%sT 1995 Sep lastSun
4:00 E-EurAsia AQT%sT
-# Kirgizstan
+# Kyrgyzstan (Kirgizstan)
+# Transitions through 1991 are from Shanks.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Kirgiz 1992 max - Apr Sun>=7 0:00 1:00 S
-Rule Kirgiz 1991 max - Sep lastSun 0:00 0 -
+Rule Kirgiz 1992 1996 - Apr Sun>=7 0:00 1:00 S
+Rule Kirgiz 1992 1996 - Sep lastSun 0:00 0 -
+Rule Kirgiz 1997 max - Mar lastSun 2:30 1:00 S
+Rule Kirgiz 1997 max - Oct lastSun 2:30 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2
- 5:00 - FRUT 1957 Mar # Frunze Time
+ 5:00 - FRUT 1930 Jun 21 # Frunze Time
6:00 RussiaAsia FRU%sT 1991 Mar 31 2:00s
- 5:00 1:00 FRUST 1991 Aug 31 # independence
+ 5:00 1:00 FRUST 1991 Aug 31 2:00 # independence
5:00 Kirgiz KG%sT # Kirgizstan Time
###############################################################################
-# Korea
+# Korea (North and South)
# From Guy Harris:
# According to someone at the Korean Times in San Francisco,
# Daylight Savings Time was not observed until 1987. He did not know
# at what time of day DST starts or ends.
-# From Shanks (1991):
+# From Shanks:
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule ROK 1960 only - May 15 0:00 1:00 D
Rule ROK 1960 only - Sep 13 0:00 0 S
# Laos
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Vientiane 6:50:24 - LMT 1906 Jun 9
+Zone Asia/Vientiane 6:50:24 - LMT 1906 Jun 9 # or Viangchan
7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT?
7:00 - ICT 1912 May
8:00 - ICT 1931 May
Rule Lebanon 1990 1992 - May 1 0:00 1:00 S
Rule Lebanon 1992 only - Oct 4 0:00 0 -
Rule Lebanon 1993 max - Mar lastSun 0:00 1:00 S
-Rule Lebanon 1993 max - Sep lastSun 0:00 0 -
+Rule Lebanon 1993 1998 - Sep lastSun 0:00 0 -
+Rule Lebanon 1999 max - Oct lastSun 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Beirut 2:22:00 - LMT 1880
2:00 Lebanon EE%sT
5:00 - MVT # Maldives Time
# Mongolia
-# Shanks says that Mongolia has three time zones, but usno1995 and
-# <URL:http://www.odci.gov/cia/publications/95fact/802389h.gif> (1995)
+
+# Shanks says that Mongolia has three time zones, but usno1995 and the CIA map
+# Standard Time Zones of the World (1997-01)
# both say that it has just one.
-# Let's comment out the western and eastern Mongolian time zones
-# till we know what their principal towns are.
+
+# From Oscar van Vlijmen (1999-12-11):
+# <a href="http://www.mongoliatourism.gov.mn/general.htm">
+# General Information Mongolia
+# </a> (1999-09)
+# "Time: Mongolia has two time zones. Three westernmost provinces of
+# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
+# the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
+# eight hours."
+
+# From Rives McDow (1999-12-13):
+# Mongolia discontinued the use of daylight savings time in 1999; 1998
+# being the last year it was implemented. The dates of implementation I am
+# unsure of, but most probably it was similar to Russia, except for the time
+# of implementation may have been different....
+# Some maps in the past have indicated that there was an additional time
+# zone in the eastern part of Mongolia, including the provinces of Dornod,
+# Suhbaatar, and possibly Khentij.
+
+# From Paul Eggert (1999-12-15):
+# For now, we'll comment out the east zone (Choybalsan)
+# and use Shanks's and the IATA's data for the daylight-saving rules.
+# Naming and spelling is tricky in Mongolia.
+# We'll use Hovd (also spelled Chovd and Khovd) to represent the west zone;
+# the capital of the Hovd province is sometimes called Hovd, sometimes Dund-Us,
+# and sometimes Jirgalanta (with variant spellings), but the name Hovd
+# is good enough for our purposes.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Mongol 1981 1984 - Apr 1 0:00 1:00 S
Rule Mongol 1981 1984 - Oct 1 0:00 0 -
Rule Mongol 1985 1990 - Mar lastSun 2:00 1:00 S
Rule Mongol 1985 1990 - Sep lastSun 3:00 0 -
-Rule Mongol 1991 max - Mar lastSun 0:00 1:00 S
+Rule Mongol 1991 1998 - Mar lastSun 0:00 1:00 S
Rule Mongol 1991 1995 - Sep lastSun 0:00 0 -
-Rule Mongol 1996 max - Oct Fri>=22 0:00 0 -
+# IATA SSIM (1996-09) says 1996-10-25; go with Shanks.
+Rule Mongol 1996 only - Oct lastSun 0:00 0 -
+Rule Mongol 1997 1998 - Sep lastSun 0:00 0 -
+# IATA SSIM (1999-09) says Mongolia no longer observes DST.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-#Zone Asia/Dariv 6:14:32 - LMT 1905 Aug
-# 6:00 - DART 1978 # Dariv Time
-# 7:00 Mongol DAR%sT
-Zone Asia/Ulan_Bator 7:07:32 - LMT 1905 Aug
- 7:00 - ULAT 1978 # Ulan Bator Time
+Zone Asia/Hovd 6:06:36 - LMT 1905 Aug
+ 6:00 - HOVT 1978 # Hovd Time
+ 7:00 Mongol HOV%sT
+Zone Asia/Ulaanbaatar 7:07:32 - LMT 1905 Aug
+ 7:00 - ULAT 1978 # Ulaanbaatar Time
8:00 Mongol ULA%sT
-#Zone Asia/Baruun-Urt 7:33:00 - LMT 1905 Aug
-# 8:00 - BART 1978 # Baruun-Urt Time
-# 9:00 Mongol BAR%sT
+# We're not sure about this entry yet, so we'll omit it for now.
+#Zone Asia/Choybalsan 7:38:00 - LMT 1905 Aug
+# 8:00 - CHOT 1978 # Choybalsan Time
+# 9:00 Mongol CHO%sT 19??
+# 8:00 Mongol ULA%sT
# Nepal
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
5:00 - PKT # Pakistan Time
# Palestine
-# These rules for Egypt are stolen from the `africa' file.
+
+# From Amos Shapir <amos@nsof.co.il> (1998-02-15):
+#
+# From 1917 until 1948-05-15, all of Palestine, including the parts now
+# known as the Gaza Strip and the West Bank, was under British rule.
+# Therefore the rules given for Israel for that period, apply there too...
+#
+# The Gaza Strip was under Egyptian rule between 1948-05-15 until 1967-06-05
+# (except a short occupation by Israel from 1956-11 till 1957-03, but no
+# time zone was affected then). It was never formally annexed to Egypt,
+# though.
+#
+# The rest of Palestine was under Jordanian rule at that time, formally
+# annexed in 1950 as the West Bank (and the word "Trans" was dropped from
+# the country's previous name of "the Hashemite Kingdom of the
+# Trans-Jordan"). So the rules for Jordan for that time apply. Major
+# towns in that area are Nablus (Shchem), El-Halil (Hebron), Ramallah, and
+# East Jerusalem.
+#
+# Both areas were occupied by Israel in June 1967, but not annexed (except
+# for East Jerusalem). They were on Israel time since then; there might
+# have been a Military Governor's order about time zones, but I'm not aware
+# of any (such orders may have been issued semi-annually whenever summer
+# time was in effect, but maybe the legal aspect of time was just neglected).
+#
+# The Palestinian Authority was established in 1993, and got hold of most
+# towns in the West Bank and Gaza by 1995. I know that in order to
+# demonstrate...independence, they have been switching to
+# summer time and back on a different schedule than Israel's, but I don't
+# know when this was started, or what algorithm is used (most likely the
+# Jordanian one).
+#
+# To summarize, the table should probably look something like that:
+#
+# Area \ when | 1918-1947 | 1948-1967 | 1967-1995 | 1996-
+# ------------+-----------+-----------+-----------+-----------
+# Israel | Zion | Zion | Zion | Zion
+# West bank | Zion | Jordan | Zion | Jordan
+# Gaza | Zion | Egypt | Zion | Jordan
+#
+# I guess more info may be available from the PA's web page (if/when they
+# have one).
+
+# From Paul Eggert (1998-02-25):
+# Shanks writes that Gaza did not observe DST until 1957, but we'll go
+# with Shapir and assume that it observed DST from 1940 through 1947,
+# and that it used Jordanian rules starting in 1996.
+# We don't yet need a separate entry for the West Bank, since
+# the only differences between it and Gaza that we know about
+# occurred before our cutoff date of 1970.
+# However, as we get more information, we may need to add entries
+# for parts of the West Bank as they transitioned from Israel's rules
+# to Palestine's rules. If you have more info about this, please
+# send it to tz@elsie.nci.nih.gov for incorporation into future editions.
+
+# From IINS News Service - Israel - 1998-03-23 10:38:07 Israel time,
+# forwarded by Ephraim Silverberg:
+#
+# Despite the fact that Israel changed over to daylight savings time
+# last week, the PLO Authority (PA) has decided not to turn its clocks
+# one-hour forward at this time. As a sign of independence from Israeli rule,
+# the PA has decided to implement DST in April.
+
+# From Paul Eggert (1999-09-20):
+# Daoud Kuttab writes in
+# <a href="http://www.jpost.com/com/Archive/22.Apr.1999/Opinion/Article-2.html">
+# Holiday havoc
+# </a> (Jerusalem Post, 1999-04-22) that
+# the Palestinian National Authority changed to DST on 1999-04-15.
+# I vaguely recall that they switch back in October (sorry, forgot the source).
+# For now, let's assume that the spring switch was at 24:00,
+# and that they switch at 0:00 on the 3rd Fridays of April and October.
+
+# The rules for Egypt are stolen from the `africa' file.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule EgyptAsia 1957 only - May 10 0:00 1:00 S
Rule EgyptAsia 1957 1958 - Oct 1 0:00 0 -
Rule EgyptAsia 1959 1967 - May 1 1:00 1:00 S
Rule EgyptAsia 1959 1965 - Sep 30 3:00 0 -
Rule EgyptAsia 1966 only - Oct 1 3:00 0 -
+
+Rule Palestine 1999 max - Apr Fri>=15 0:00 1:00 S
+Rule Palestine 1999 max - Oct Fri>=15 0:00 0 -
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
- 2:00 - EET 1957 May 10
- 2:00 EgyptAsia EE%sT 1967 Jun 30
- 2:00 Zion I%sT
+ 2:00 Zion EET 1948 May 15
+ 2:00 EgyptAsia EE%sT 1967 Jun 5
+ 2:00 Zion I%sT 1996
+ 2:00 Jordan EE%sT 1999
+ 2:00 Palestine EE%sT
# Paracel Is
# no information
# Philippines
-# Howse writes (p 162) that until 1844 the Philippines kept American date.
+# On 1844-08-16, Narciso Claveria, governor-general of the
+# Philippines, issued a proclamation announcing that 1844-12-30 was to
+# be immediately followed by 1845-01-01. Robert H. van Gent has a
+# transcript of the decree in <http://www.phys.uu.nl/~vgent/idl/idl.htm>.
# The rest of this data is from Shanks.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Phil 1936 only - Nov 1 0:00 1:00 S
Rule Phil 1978 only - Mar 22 0:00 1:00 S
Rule Phil 1978 only - Sep 21 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Manila -15:56:00 - LMT 1844
+Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31
8:04:00 - LMT 1899 May 11
8:00 Phil PH%sT 1942 May
9:00 - JST 1944 Nov
# Qatar
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah
+Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha
4:00 - GST 1972 Jun
3:00 - AST
# Sri Lanka
# From Paul Eggert (1996-09-03):
-# <URL:http://www.virtual-pc.com/lankaweb/news/items/240596-2.html> (1996-05-24)
+# "Sri Lanka advances clock by an hour to avoid blackout"
+# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
+# no longer available as of 1999-08-17)
# reported ``the country's standard time will be put forward by one hour at
# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
-# Transitions before 1996 are from Shanks (1991).
+#
+# From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
+# by Shamindra in
+# <a href="news:54rka5$m5h@mtinsc01-mgt.ops.worldnet.att.net">
+# Daily News - Hot News Section (1996-10-26)
+# </a>:
+# With effect from 12.30 a.m. on 26th October 1996
+# Sri Lanka will be six (06) hours ahead of GMT.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Colombo 5:19:24 - LMT 1880
- 5:20 - CEYT 1906 # Ceylon Time
+ 5:19:32 - MMT 1906 # Moratuwa Mean Time
5:30 - IST 1942 Jan 5
5:30 0:30 IHST 1942 Sep
5:30 1:00 IST 1945 Oct 16 2:00
5:30 - IST 1996 May 25 0:00
- 6:30 - LKT # Sri Lanka Time
+ 6:30 - LKT 1996 Oct 26 0:30
+ 6:00 - LKT
# Syria
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Syria 1992 only - Apr 8 0:00 1:00 S
Rule Syria 1993 only - Mar 26 0:00 1:00 S
Rule Syria 1993 only - Sep 25 0:00 0 -
-# IATA SSIM (1996-09) says 1997-03-31; assume that it should be 1997-04-01.
-Rule Syria 1994 max - Apr 1 0:00 1:00 S
+# IATA SSIM (1998-02) says 1998-04-02;
+# (1998-09) says 1999-03-29 and 1999-09-29; (1999-02) says 1999-04-02,
+# 2000-04-02, and 2001-04-02; (1999-09) says 2000-03-31 and 2001-03-31;
+# ignore all these claims and go with Shanks.
+Rule Syria 1994 1996 - Apr 1 0:00 1:00 S
Rule Syria 1994 max - Oct 1 0:00 0 -
+Rule Syria 1997 1998 - Mar lastMon 0:00 1:00 S
+Rule Syria 1999 max - Apr 1 0:00 1:00 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Damascus 2:25:12 - LMT 1920
+Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq
2:00 Syria EE%sT
# Tajikistan
+# From Shanks.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
- 5:00 - DUST 1957 Mar # Dushanbe Time
+ 5:00 - DUST 1930 Jun 21 # Dushanbe Time
6:00 RussiaAsia DUS%sT 1991 Mar 31 2:00s
- 5:00 1:00 DUSST 1991 Sep 9 # independence
- 5:00 RussiaAsia TJ%sT 1992
+ 5:00 1:00 DUSST 1991 Sep 9 2:00s
5:00 - TJT # Tajikistan Time
# Thailand
7:00 - ICT
# Turkmenistan
+# From Shanks.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Asia/Ashkhabad 3:53:32 - LMT 1924 May 2 # or Ashgabat
- 4:00 - ASHT 1957 Mar # Ashkhabad Time
- 5:00 RussiaAsia ASH%sT 1991 Mar 31 2:00s
- 4:00 1:00 ASHST 1991 Sep 29 2:00s
- 4:00 - ASHT 1991 Oct 27 # independence
- 4:00 - TMT 1992 Jan 19 2:00s
- 5:00 - TMT # Turkmenistan Time
+Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad
+ 4:00 - ASHT 1930 Jun 21 # Ashkhabad Time
+ 5:00 RussiaAsia ASH%sT 1991 Mar 31 2:00
+ 4:00 RussiaAsia ASH%sT 1991 Oct 27 # independence
+ 4:00 RussiaAsia TM%sT 1992 Jan 19 2:00
+ 5:00 - TMT
# United Arab Emirates
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Uzbekistan
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Asia/Samarkand 4:27:12 - LMT 1924 May 2
+ 4:00 - SAMT 1930 Jun 21 # Samarkand Time
+ 5:00 - SAMT 1981 Apr 1
+ 5:00 1:00 SAMST 1981 Oct 1
+ 6:00 RussiaAsia TAS%sT 1991 Mar 31 2:00 # Tashkent Time
+ 5:00 RussiaAsia TAS%sT 1991 Sep 1 # independence
+ 5:00 RussiaAsia UZ%sT 1992
+ 5:00 RussiaAsia UZ%sT 1993
+ 5:00 - UZT
Zone Asia/Tashkent 4:37:12 - LMT 1924 May 2
- 5:00 - TAST 1957 Mar # Tashkent Time
+ 5:00 - TAST 1930 Jun 21 # Tashkent Time
6:00 RussiaAsia TAS%sT 1991 Mar 31 2:00s
- 5:00 1:00 TASST 1991 Sep 29 2:00s
- 5:00 - UZT # Uzbekistan Time
-# Shanks has Tashkent using DST after 1991, but usno1995 says they don't.
-# Guess no DST after 1991.
-# <URL:http://www.odci.gov/cia/publications/95fact/802389h.gif> (1995)
-# says that Uzbekistan has two time zones, but a cable
-# <URL:http://www.itaiep.doc.gov/bisnis/cables/960510uz.html> (1996-05-10)
-# from the American Embassy in Tashkent implies that they have just one.
+ 5:00 RussiaAsia TAS%sT 1991 Sep 1 # independence
+ 5:00 RussiaAsia UZ%sT 1992
+ 5:00 RussiaAsia UZ%sT 1993
+ 5:00 - UZT
# Vietnam
# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
# Saigon's official name is Thanh-Pho Ho Chi Minh, but it's too long.
# We'll stick with the traditional name for now.
-# From Shanks (1991):
+# From Shanks:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Saigon 7:06:40 - LMT 1906 Jun 9
7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT?
-# $OpenBSD: australasia,v 1.5 1997/01/14 04:36:50 millert Exp $
-# @(#)australasia 7.31
+# @(#)australasia 7.64
# This file also includes Pacific islands.
-
+# $FreeBSD: src/share/zoneinfo/australasia,v 1.19 2001/05/01 14:10:12 schweikh Exp $
# Notes are at the end of this file
###############################################################################
# Australia
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-# Shanks gives 1917 Jan 1 0:01; go with Whitman (and guess 2:00).
-Rule Aus 1916 only - Oct 1 2:00 1:00 -
+Rule Aus 1917 only - Jan 1 0:01 1:00 -
Rule Aus 1917 only - Mar 25 2:00 0 -
Rule Aus 1942 only - Jan 1 2:00 1:00 -
Rule Aus 1942 only - Mar 29 2:00 0 -
Rule Aus 1942 only - Sep 27 2:00 1:00 -
Rule Aus 1943 1944 - Mar lastSun 2:00 0 -
Rule Aus 1943 only - Oct 3 2:00 1:00 -
-# Whitman says W Australia didn't use DST in 1943/1944, and that
-# 1944/1945 was just like 1943/1944; go with Shanks.
+# Go with Whitman and the Australian National Standards Commission, which
+# says W Australia didn't use DST in 1943/1944. Ignore Whitman's claim that
+# 1944/1945 was just like 1943/1944.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Northern Territory
Zone Australia/Darwin 8:43:20 - LMT 1895 Feb
- 9:30 - CST 1917 Jan 1 0:01
+ 9:00 - CST 1899 May
9:30 Aus CST
# Western Australia
Zone Australia/Perth 7:43:24 - LMT 1895 Dec
- 8:00 - WST 1917 Jan 1 0:01
- 8:00 Aus WST 1974 Oct lastSun 2:00s
+ 8:00 Aus WST 1943 Jul
+ 8:00 - WST 1974 Oct lastSun 2:00s
8:00 1:00 WST 1975 Mar Sun>=1 2:00s
8:00 - WST 1983 Oct lastSun 2:00s
8:00 1:00 WST 1984 Mar Sun>=1 2:00s
# so use Lindeman.
#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule AQ 1971 only - Oct lastSun 2:00s 1:00 -
+Rule AQ 1972 only - Feb lastSun 2:00s 0 -
Rule AQ 1989 1991 - Oct lastSun 2:00s 1:00 -
Rule AQ 1990 1992 - Mar Sun>=1 2:00s 0 -
-Rule Holiday 1989 1993 - Oct lastSun 2:00s 1:00 -
-Rule Holiday 1990 1994 - Mar Sun>=1 2:00s 0 -
+Rule Holiday 1992 1993 - Oct lastSun 2:00s 1:00 -
+Rule Holiday 1993 1994 - Mar Sun>=1 2:00s 0 -
Zone Australia/Brisbane 10:12:08 - LMT 1895
- 10:00 - EST 1917 Jan 1 0:01
- 10:00 Aus EST 1971 Oct lastSun 2:00s
- 10:00 1:00 EST 1972 Feb lastSun 2:00s
+ 10:00 Aus EST 1971
10:00 AQ EST
Zone Australia/Lindeman 9:55:56 - LMT 1895
- 10:00 - EST 1917 Jan 1 0:01
- 10:00 Aus EST 1971 Oct lastSun 2:00s
- 10:00 1:00 EST 1972 Feb lastSun 2:00s
+ 10:00 Aus EST 1971
+ 10:00 AQ EST 1992 Jul
10:00 Holiday EST
# South Australia
Rule AS 1972 only - Feb 27 2:00s 0 -
Rule AS 1973 1985 - Mar Sun>=1 2:00s 0 -
Rule AS 1986 1989 - Mar Sun>=15 2:00s 0 -
-Rule AS 1990 1994 even Mar Sun>=18 2:00s 0 -
-Rule AS 1990 1994 odd Mar Sun>=1 2:00s 0 -
+Rule AS 1990 only - Mar Sun>=18 2:00s 0 -
+Rule AS 1991 only - Mar Sun>=1 2:00s 0 -
+Rule AS 1992 only - Mar Sun>=18 2:00s 0 -
+Rule AS 1993 only - Mar Sun>=1 2:00s 0 -
+Rule AS 1994 only - Mar Sun>=18 2:00s 0 -
Rule AS 1995 max - Mar lastSun 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Australia/Adelaide 9:14:20 - LMT 1895 Feb
9:00 - CST 1899 May
- 9:30 - CST 1917 Jan 1 0:01
- 9:30 Aus CST 1971 Oct lastSun 2:00s
+ 9:30 Aus CST 1971
9:30 AS CST
# Tasmania
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule AT 1967 only - Oct 1 2:00s 1:00 -
-Rule AT 1968 only - Mar 31 2:00s 0 -
+Rule AT 1967 only - Oct Sun>=1 2:00s 1:00 -
+Rule AT 1968 only - Mar lastSun 2:00s 0 -
Rule AT 1968 1985 - Oct lastSun 2:00s 1:00 -
Rule AT 1969 1971 - Mar Sun>=8 2:00s 0 -
-Rule AT 1972 only - Feb 27 2:00s 0 -
+Rule AT 1972 only - Feb lastSun 2:00s 0 -
Rule AT 1973 1981 - Mar Sun>=1 2:00s 0 -
Rule AT 1982 1983 - Mar lastSun 2:00s 0 -
Rule AT 1984 1986 - Mar Sun>=1 2:00s 0 -
-Rule AT 1986 only - Oct 19 2:00s 1:00 -
+Rule AT 1986 only - Oct Sun>=15 2:00s 1:00 -
Rule AT 1987 1990 - Mar Sun>=15 2:00s 0 -
-Rule AT 1987 1990 - Oct lastSun 2:00s 1:00 -
-Rule AT 1991 max - Oct Sun>=1 2:00s 1:00 -
+Rule AT 1987 only - Oct Sun>=22 2:00s 1:00 -
+Rule AT 1988 1990 - Oct lastSun 2:00s 1:00 -
+Rule AT 1991 1999 - Oct Sun>=1 2:00s 1:00 -
Rule AT 1991 max - Mar lastSun 2:00s 0 -
+Rule AT 2000 only - Aug lastSun 2:00s 1:00 -
+Rule AT 2001 max - Oct Sun>=1 2:00s 1:00 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Australia/Hobart 9:49:16 - LMT 1895 Sep
- 10:00 - EST 1917 Jan 1 0:01
- 10:00 Aus EST 1967 Oct 1 2:00s
+ 10:00 - EST 1916 Oct 1 2:00
+ 10:00 1:00 EST 1917 Feb
+ 10:00 Aus EST 1967
10:00 AT EST
# Victoria
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule AV 1971 1985 - Oct lastSun 2:00s 1:00 -
-Rule AV 1972 only - Feb 27 2:00s 0 -
+Rule AV 1972 only - Feb lastSun 2:00s 0 -
Rule AV 1973 1985 - Mar Sun>=1 2:00s 0 -
Rule AV 1986 1990 - Mar Sun>=15 2:00s 0 -
-Rule AV 1986 only - Oct 19 2:00s 1:00 -
-Rule AV 1987 max - Oct lastSun 2:00s 1:00 -
+Rule AV 1986 1987 - Oct Sun>=15 2:00s 1:00 -
+Rule AV 1988 1999 - Oct lastSun 2:00s 1:00 -
Rule AV 1991 1994 - Mar Sun>=1 2:00s 0 -
Rule AV 1995 max - Mar lastSun 2:00s 0 -
+Rule AV 2000 only - Aug lastSun 2:00s 1:00 -
+Rule AV 2001 max - Oct lastSun 2:00s 1:00 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Australia/Melbourne 9:39:52 - LMT 1895 Feb
- 10:00 - EST 1917 Jan 1 0:01
- 10:00 Aus EST 1971 Oct 31 2:00s
+ 10:00 Aus EST 1971
10:00 AV EST
# New South Wales
Rule AN 1983 1985 - Mar Sun>=1 2:00s 0 -
Rule AN 1986 1989 - Mar Sun>=15 2:00s 0 -
Rule AN 1986 only - Oct 19 2:00s 1:00 -
-Rule AN 1987 max - Oct lastSun 2:00s 1:00 -
+Rule AN 1987 1999 - Oct lastSun 2:00s 1:00 -
Rule AN 1990 1995 - Mar Sun>=1 2:00s 0 -
Rule AN 1996 max - Mar lastSun 2:00s 0 -
+Rule AN 2000 only - Aug lastSun 2:00s 1:00 -
+Rule AN 2001 max - Oct lastSun 2:00s 1:00 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Australia/Sydney 10:04:52 - LMT 1895 Feb
- 10:00 - EST 1917 Jan 1 0:01
- 10:00 Aus EST 1971 Oct 31 2:00s
+ 10:00 Aus EST 1971
10:00 AN EST
Zone Australia/Broken_Hill 9:25:48 - LMT 1895 Feb
10:00 - EST 1896 Aug 23
9:00 - CST 1899 May
- 9:30 - CST 1917 Jan 1 0:01
- 9:30 Aus CST 1971 Oct 31 2:00s
- 9:30 AN CST
+ 9:30 Aus CST 1971
+ 9:30 AN CST 2000
+ 9:30 AS CST
# Lord Howe Island
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule LH 1981 1984 - Oct lastSun 2:00s 1:00 -
-Rule LH 1982 1985 - Mar Sun>=1 2:00s 0 -
-Rule LH 1985 only - Oct lastSun 2:00s 0:30 -
-Rule LH 1986 1989 - Mar Sun>=15 2:00s 0 -
-Rule LH 1986 only - Oct 19 2:00s 0:30 -
-Rule LH 1987 max - Oct lastSun 2:00s 0:30 -
-Rule LH 1990 1995 - Mar Sun>=1 2:00s 0 -
-Rule LH 1996 max - Mar lastSun 2:00s 0 -
+Rule LH 1981 1984 - Oct lastSun 2:00 1:00 -
+Rule LH 1982 1985 - Mar Sun>=1 2:00 0 -
+Rule LH 1985 only - Oct lastSun 2:00 0:30 -
+Rule LH 1986 1989 - Mar Sun>=15 2:00 0 -
+Rule LH 1986 only - Oct 19 2:00 0:30 -
+Rule LH 1987 1999 - Oct lastSun 2:00 0:30 -
+Rule LH 1990 1995 - Mar Sun>=1 2:00 0 -
+Rule LH 1996 max - Mar lastSun 2:00 0 -
+Rule LH 2000 only - Aug lastSun 2:00 0:30 -
+Rule LH 2001 max - Oct lastSun 2:00 0:30 -
Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb
10:00 - EST 1981 Mar
10:30 LH LHST
# Australian miscellany
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Indian/Christmas 7:02:52 - LMT 1895 Feb
- 7:00 - CXT # Christmas Island Time
#
# Ashmore Is, Cartier
# no indigenous inhabitants; only seasonal caretakers
-# no information; probably like Australia/Perth
+# like Australia/Perth, says Turner
#
# Coral Sea Is
# no indigenous inhabitants; only meteorologists
# no information
#
-# Macquarie, Manihiki, Penrhyn, Rakehanga
-# no information
+# Macquarie
+# permanent occupation (scientific station) since 1948;
+# sealing and penguin oil station operated 1888/1917
+# like Australia/Hobart, says Turner
+# Christmas
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Indian/Christmas 7:02:52 - LMT 1895 Feb
+ 7:00 - CXT # Christmas Island Time
# Cook Is
+# From Shanks:
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Cook 1978 only - Nov 12 0:00 0:30 HS
-Rule Cook 1979 max - Mar Sun>=1 0:00 0 -
-Rule Cook 1979 max - Oct lastSun 0:00 0:30 HS
+Rule Cook 1979 1991 - Mar Sun>=1 0:00 0 -
+Rule Cook 1979 1990 - Oct lastSun 0:00 0:30 HS
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Rarotonga -10:39:04 - LMT 1901 # Avarua
-10:30 - CKT 1978 Nov 12 # Cook Is Time
Zone Indian/Cocos 6:30 - CCT # Cocos Islands Time
# Fiji
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 S
+Rule Fiji 1999 2000 - Feb lastSun 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Fiji 11:53:40 - LMT 1915 Oct 26 # Suva
- 12:00 - FJT # Fiji Time
+ 12:00 Fiji FJ%sT # Fiji Time
# French Polynesia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-9:30 - MART # Marquesas Time
Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct # Papeete
-10:00 - TAHT # Tahiti Time
+# Clipperton (near North America) is administered from French Polynesia;
+# it is uninhabited.
# Guam
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Pacific/Guam 9:39:00 - LMT 1901 # Agana
- 10:00 - GST
-
-# Howland, Baker
-# uninhabited since World War II
-# no information; was probably like Pacific/Pago_Pago
-
-# Jarvis
-# uninhabited since 1958
-# no information; was probably like Pacific/Kiritimati
-
-# Johnston
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Pacific/Johnston -10:00 - HST
-
-# Kingman
-# uninhabited
+Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31
+ 9:39:00 - LMT 1901 # Agana
+ 10:00 - GST 2000 Dec 23 # Guam
+ 10:00 - ChST # Chamorro Standard Time
# Kiribati
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# N Mariana Is
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Pacific/Saipan 9:43:00 - LMT 1901
+Zone Pacific/Saipan -14:17:00 - LMT 1844 Dec 31
+ 9:43:00 - LMT 1901
9:00 - MPT 1969 Oct # N Mariana Is Time
- 10:00 - MPT
+ 10:00 - MPT 2000 Dec 23
+ 10:00 - ChST # Chamorro Standard Time
# Marshall Is
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Ponape 10:32:52 - LMT 1901 # Kolonia
11:00 - PONT # Ponape Time
Zone Pacific/Kosrae 10:51:56 - LMT 1901
- 11:00 - PONT 1969 Oct
- 12:00 - KOST # Kosrae Time
+ 11:00 - KOST 1969 Oct # Kosrae Time
+ 12:00 - KOST 1999
+ 11:00 - KOST
# Nauru
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule NC 1977 1978 - Dec Sun>=1 0:00 1:00 S
Rule NC 1978 1979 - Feb 27 0:00 0 -
+Rule NC 1996 only - Dec 1 2:00s 1:00 S
+# Shanks says the following was at 2:00; go with IATA.
+Rule NC 1997 only - Mar 2 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13
11:00 NC NC%sT
Rule NZ 1929 only - Oct 30 2:00 0:30 HD
Rule NZ 1930 1933 - Mar Sun>=15 2:00 0 S
Rule NZ 1930 1933 - Oct Sun>=8 2:00 0:30 HD
-# Whitman says DST went on and off during war years, and the base GMT offset
+# Whitman says DST went on and off during war years, and the base UT offset
# didn't change until 1945 Apr 30; go with Shanks.
Rule NZ 1934 1940 - Apr lastSun 2:00 0 S
Rule NZ 1934 1939 - Sep lastSun 2:00 0:30 HD
Zone Pacific/Chatham 12:45 Chatham CHA%sT
-# Antipodes Is, Kermadec Is
-# uninhabited except by research personnel; probably like Pacific/Auckland
+# Auckland Is
+# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
+# and scientific personnel have wintered
+
+# Campbell I
+# minor whaling stations operated 1909/1914
+# scientific station operated 1941/1995;
+# previously whalers, sealers, pastoralists, and scientific personnel wintered
+# was probably like Pacific/Auckland
###############################################################################
11:12 - NMT 1951 # Norfolk Mean Time
11:30 - NFT # Norfolk Time
-# Palau
+# Palau (Belau)
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Palau 8:57:56 - LMT 1901 # Koror
9:00 - PWT # Palau Time
-# Palmyra
-# uninhabited since World War II; was probably like Pacific/Kiritimati
-
# Papua New Guinea
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Port_Moresby 9:48:40 - LMT 1880
# Pitcairn
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown
- -8:30 - PNT # Pitcairn Time
+ -8:30 - PNT 1998 Apr 27 00:00
+ -8:00 - PST # Pitcairn Standard Time
# American Samoa
Zone Pacific/Pago_Pago 12:37:12 - LMT 1879 Jul 5
-10:00 - TKT # Tokelau Time
# Tonga
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Tonga 1999 only - Oct 7 2:00s 1:00 S
+Rule Tonga 2000 only - Mar 19 2:00s 0 -
+Rule Tonga 2000 only - Nov 4 2:00s 1:00 S
+Rule Tonga 2001 only - Jan 27 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Tongatapu 12:19:20 - LMT 1901
- 12:20 - TOT 1968 Oct # Tonga Time
- 13:00 - TOT
+ 12:20 - TOT 1941 # Tonga Time
+ 13:00 - TOT 1999
+ 13:00 Tonga TO%sT
# Tuvalu
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Funafuti 11:56:52 - LMT 1901
12:00 - TVT # Tuvalu Time
+
+# US minor outlying islands
+
+# Howland, Baker
+# uninhabited since World War II
+# no information; was probably like Pacific/Pago_Pago
+
+# Jarvis
+# uninhabited since 1958
+# no information; was probably like Pacific/Kiritimati
+
+# Johnston
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Pacific/Johnston -10:00 - HST
+
+# Kingman
+# uninhabited
+
+# Midway
+Zone Pacific/Midway -11:49:28 - LMT 1901
+ -11:00 - NST 1967 Apr # N=Nome
+ -11:00 - BST 1983 Nov 30 # B=Bering
+ -11:00 - SST # S=Samoa
+
+# Palmyra
+# uninhabited since World War II; was probably like Pacific/Kiritimati
+
+# Wake
+# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+Zone Pacific/Wake 11:06:28 - LMT 1901
+ 12:00 - WAKT # Wake Time
+
+
# Vanuatu
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Vanuatu 1983 only - Sep 25 0:00 1:00 S
Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila
11:00 Vanuatu VU%sT # Vanuatu Time
-# Wake
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Pacific/Wake 11:06:28 - LMT 1901
- 12:00 - WAKT # Wake Time
-
# Wallis and Futuna
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Wallis 12:15:20 - LMT 1901
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-10-29):
# A good source for time zone historical data outside the U.S. is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# I found in the UCLA library.
#
# A reliable and entertaining source about time zones is
-# Derek Howse, Greenwich time and the discovery of the longitude,
-# Oxford University Press (1980).
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
#
# I invented the abbreviations marked `*' in the following table;
# the rest are from earlier versions of this file, or from other sources.
# 9:00 JST Japan
# 9:30 CST CST Central Australia
# 10:00 EST EST Eastern Australia
-# 10:00 GST Guam
+# 10:00 ChST Chamorro
# 10:30 LHST LHST Lord Howe*
# 12:00 NZST NZDT New Zealand
# 12:45 CHAST CHADT Chatham*
# -11:00 SST Samoa
# -10:00 HST Hawaii
+# - 8:00 PST Pitcairn*
#
# See the `northamerica' file for Hawaii.
# See the `southamerica' file for Easter I and the Galapagos Is.
-#
-# See the `africa' file for time zone naming and abbreviation conventions.
###############################################################################
# Australia
+# <a href="http://www.dstc.qut.edu.au/DST/marg/daylight.html">
+# Australia's Daylight Saving Times
+# </a>, by Margaret Turner, summarizes daylight saving issues in Australia.
+
# From John Mackin (1991-03-06):
# We in Australia have _never_ referred to DST as `daylight' time.
# It is called `summer' time. Now by a happy coincidence, `summer'
# and perhaps the newspaper's `2:00' is referring to standard time.
# For now we'll continue to assume 2:00s for changes since 1960.
+# From Eric Ulevik <eau@zip.com.au> (1998-01-05):
+#
+# Here are some URLs to Australian time legislation. These URLs are stable,
+# and should probably be included in the data file. There are probably more
+# relevant entries in this database.
+#
+# NSW (including LHI and Broken Hill):
+# <a href="http://www.austlii.edu.au/au/legis/nsw/consol_act/sta1987137/index.html">
+# Standard Time Act 1987 (updated 1995-04-04)
+# </a>
+# ACT
+# <a href="http://www.austlii.edu.au/au/legis/act/consol_act/stasta1972279/index.html">
+# Standard Time and Summer Time Act 1972
+# </a>
+# SA
+# <a href="http://www.austlii.edu.au/au/legis/sa/consol_act/sta1898137/index.html">
+# Standard Time Act, 1898
+# </a>
+
# Northern Territory
# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
# The 1992 ending date used in the rules is a best guess;
# it matches what was used in the past.
+# <a href="http://www.bom.gov.au/faq/faqgen.htm">
+# The Australian Bureau of Meteorology FAQ
+# </a> (1999-09-27) writes that Giles Meteorological Station uses
+# South Australian time even though it's located in Western Australia.
+
# Queensland
# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
# # The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
# Tasmania
-# From Bradley White (1991-03-04):
-# A recent excerpt from an Australian newspaper...
-# ...Tasmania will revert to Australian Eastern Standard Time on March 31...
-
-# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# The rules for 1967 through 1991 were reported by George Shepherd
+# via Simon Woodhead via Robert Elz (1991-03-06):
# # The state of TASMANIA.. [Courtesy Tasmanian Dept of Premier + Cabinet ]
# # [ Nov 1990 ]
-# ...
-# Zone Australia/Tasmania 10:00 AT %sST
-# ...
-# Rule AT 1967 only - Oct Sun>=1 2:00 1:00 D
-# Rule AT 1968 only - Mar lastSun 3:00 0 E
-# Rule AT 1968 1985 - Oct lastSun 2:00 1:00 D
-# Rule AT 1969 1971 - Mar Sun>=8 3:00 0 E
-# Rule AT 1972 only - Feb lastSun 3:00 0 E
-# Rule AT 1973 1981 - Mar Sun>=1 3:00 0 E
-# Rule AT 1982 1983 - Mar lastSun 3:00 0 E
-# Rule AT 1984 1986 - Mar Sun>=1 3:00 0 E
-# Rule AT 1986 only - Oct Sun>=15 2:00 1:00 D
-# Rule AT 1987 1990 - Mar Sun>=15 3:00 0 E
-# Rule AT 1987 only - Oct Sun>=22 2:00 1:00 D
-# Rule AT 1988 1990 - Oct lastSun 2:00 1:00 D
-# Rule AT 1991 max - Oct Sun>=1 2:00 1:00 D
-# Rule AT 1991 max - Mar lastSun 3:00 0 E
-
-# From Bill Hart via Alexander Dupuy and Guy Harris (1991-10-10):
-# My state Government in there eagerness to get a few more bucks for the
-# tourist industry industry decided to change the daylight savings times
-# yet again (we now have almost 6 months per year)...
-# ...
-# Rule Oz 1986 1990 - Oct Sun<=24 2:00 1:00 -
-# Rule Oz 1991 max - Oct Sun>=1 2:00 1:00 -
-# ...
-# Rule Oz 1987 1990 - Mar Sun<=21 3:00 0 -
-# Rule Oz 1991 max - Mar Sun<=31 3:00 0 -
# From Bill Hart via Guy Harris (1991-10-10):
# Oh yes, the new daylight savings rules are uniquely tasmanian, we have
# 6 weeks a year now when we are out of sync with the rest of Australia
# (but nothing new about that).
-# Victoria
+# From Alex Livingston (1999-10-04):
+# I heard on the ABC (Australian Broadcasting Corporation) radio news on the
+# (long) weekend that Tasmania, which usually goes its own way in this regard,
+# has decided to join with most of NSW, the ACT, and most of Victoria
+# (Australia) and start daylight saving on the last Sunday in August in 2000
+# instead of the first Sunday in October.
-# From Bradley White (1991-03-04):
-# A recent excerpt from an Australian newspaper...
-# ...Victoria...[has] agreed to end daylight saving at 3am tomorrow (March 3)...
+# Sim Alam (2000-07-03) reported a legal citation for the 2000/2001 rules:
+# http://www.thelaw.tas.gov.au/fragview/42++1968+GS3A@EN+2000070300
-# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# Victoria
+
+# The rules for 1971 through 1991 were reported by George Shepherd
+# via Simon Woodhead via Robert Elz (1991-03-06):
# # The state of VICTORIA.. [ Courtesy of Vic. Dept of Premier + Cabinet ]
# # [ Nov 1990 ]
-# ...
-# Zone Australia/Victoria 10:00 AV %sST
-# ...
-# Rule AV 1971 1985 - Oct lastSun 2:00 1:00 D
-# Rule AV 1972 only - Feb lastSun 3:00 0 E
-# Rule AV 1973 1985 - Mar Sun>=1 3:00 0 E
-# Rule AV 1986 1990 - Mar Sun>=15 3:00 0 E
-# Rule AV 1986 1987 - Oct Sun>=15 2:00 1:00 D
-# Rule AV 1988 max - Oct lastSun 2:00 1:00 D
-# Rule AV 1991 max - Mar Sun>=1 3:00 0 E
# New South Wales
# legislation. This is very important to understand.
# I have researched New South Wales time only...
-# From Dave Davey (1990-03-03):
-# Rule NSW 1988 only - Mar Sun>=1 3:00 0 -
-# Rule NSW 1989 only - Mar Sun<=21 3:00 0 -
-
-# From Bradley White (1991-03-04):
-# A recent excerpt from an Australian newspaper...
-# NSW...[has] agreed to end daylight saving at 3am tomorrow (March 3)...
-
-# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
-# # The state of NEW SOUTH WALES.. [confirmed by Attorney General's Dept N.S.W]
-# # [ Dec 1990 ]
-# ...
-# Rule AN 1988 1989 - Mar Sun<=21 3:00 0 E
-# ...
-
-# From John Mackin (1991-03-09)
-# I have confirmed the accuracy of the historical data for NSW in the
-# file Robert forwarded
+# From Paul Eggert (1999-09-27):
+# The Information Service of the Australian National Standards Commission
+# <a href="http://www.nsc.gov.au/InfoServ/Ileaflet/il27.htm">
+# Daylight Saving
+# </a> page (1995-04) has an excellent overall history of Australian DST.
+# The Community Relations Division of the NSW Attorney General's Department
+# publishes a history of daylight saving in NSW. See:
+# <a href="http://www.lawlink.nsw.gov.au/crd.nsf/pages/time2">
+# Lawlink NSW: Daylight Saving in New South Wales
+# </a>
+
+# From Eric Ulevik <eau@ozemail.com.au> (1999-05-26):
+# DST will start in NSW on the last Sunday of August, rather than the usual
+# October in 2000. [See: Matthew Moore,
+# <a href="http://www.smh.com.au/news/9905/26/pageone/pageone4.html">
+# Two months more daylight saving
+# </a>
+# Sydney Morning Herald (1999-05-26).]
+
+# From Paul Eggert (1999-09-27):
+# See the following official NSW source:
+# <a href="http://dir.gis.nsw.gov.au/cgi-bin/genobject/document/other/daylightsaving/tigGmZ">
+# Daylight Saving in New South Wales.
+# </a>
+#
+# Narrabri Shire (NSW) council has announced it will ignore the extension of
+# daylight saving next year. See:
+# <a href="http://abc.net.au/news/regionals/neweng/monthly/regeng-22jul1999-1.htm">
+# Narrabri Council to ignore daylight saving
+# </a> (1999-07-22). For now, we'll wait to see if this really happens.
+#
+# Victoria will following NSW. See:
+# <a href="http://abc.net.au/local/news/olympics/1999/07/item19990728112314_1.htm">
+# Vic to extend daylight saving
+# </a> (1999-07-28).
+#
+# However, South Australia rejected the DST request. See:
+# <a href="http://abc.net.au/news/olympics/1999/07/item19990719151754_1.htm">
+# South Australia rejects Olympics daylight savings request
+# </a> (1999-07-19).
+#
+# Queensland also will not observe DST for the Olympics. See:
+# <a href="http://abc.net.au/news/olympics/1999/06/item19990601114608_1.htm">
+# Qld says no to daylight savings for Olympics
+# </a> (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
+# ``Look you've got to remember in my family when this came up last time
+# I voted for it, my wife voted against it and she said to me it's all very
+# well for you, you don't have to worry about getting the children out of
+# bed, getting them to school, getting them to sleep at night.
+# I've been through all this argument domestically...my wife rules.''
+#
+# Broken Hill will stick with South Australian time in 2000. See:
+# <a href="http://abc.net.au/news/regionals/brokenh/monthly/regbrok-21jul1999-6.htm">
+# Broken Hill to be behind the times
+# </a> (1999-07-21).
-# From Arthur David Olson (1992-03-08):
-# Sources differ on whether DST ended March 6 or March 20 in 1988;
-# March 20 (the "confirmed" date) is in the chosen rules.
+# IATA SSIM (1998-09) says that the spring 2000 change for Australian
+# Capital Territory, New South Wales except Lord Howe Island and Broken
+# Hill, and Victoria will be August 27, presumably due to the Sydney Olympics.
-# From Bradley White (1995-05-20):
-# Prem Bob Carr announced NSW will fall into line with other E states
-# and SA and continue daylight savings to the last Sun in Mar.
+# From Eric Ulevik, referring to Sydney's Sun Herald (2000-08-13), page 29:
+# The Queensland Premier Peter Beattie is encouraging northern NSW
+# towns to use Queensland time.
# Yancowinna
-# From John Basser (1989-01-04):
+# From John Mackin (1989-01-04):
# `Broken Hill' means the County of Yancowinna.
# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
# # YANCOWINNA.. [ Confirmation courtesy of Broken Hill Postmaster ]
# # [ Dec 1990 ]
# ...
-# # Yancowinna uses Central Standard Time, despite it's location on the
+# # Yancowinna uses Central Standard Time, despite [its] location on the
# # New South Wales side of the S.A. border. Most business and social dealings
# # are with CST zones, therefore CST is legislated by local government
# # although the switch to Summer Time occurs in line with N.S.W. There have
# Lord Howe Island is located off the New South Wales coast, and is half an
# hour ahead of NSW time.
-# From Paul Eggert (1995-12-19):
-# For Lord Howe we use Shanks through its time of publication (1991).
-# Lord Howe is part of NSW, so we'll guess it has used the same transition
-# times as NSW since 1991, even though Shanks writes that Lord Howe went
-# with Victoria when NSW and Victoria disagreed in 1982.
+# From James Lonergan, Secretary, Lord Howe Island Board (2000-01-27):
+# Lord Howe Island summer time in 2000/2001 will commence on the same
+# date as the rest of NSW (i.e. 2000-08-27). For your information the
+# Lord Howe Island Board (controlling authority for the Island) is
+# seeking the community's views on various options for summer time
+# arrangements on the Island, e.g. advance clocks by 1 full hour
+# instead of only 30 minutes. Dependent on the wishes of residents
+# the Board may approach the NSW government to change the existing
+# arrangements. The starting date for summer time on the Island will
+# however always coincide with the rest of NSW.
+
+# From James Lonergan, Secretary, Lord Howe Island Board (2000-10-25):
+# Lord Howe Island advances clocks by 30 minutes during DST in NSW and retards
+# clocks by 30 minutes when DST finishes. Since DST was most recently
+# introduced in NSW, the "changeover" time on the Island has been 02:00 as
+# shown on clocks on LHI. I guess this means that for 30 minutes at the start
+# of DST, LHI is actually 1 hour ahead of the rest of NSW.
+
+# From Paul Eggert (2001-02-09):
+# For Lord Howe dates we use Shanks through 1989, and Lonergan thereafter.
+# For times we use Lonergan.
###############################################################################
-# New Zealand, from Elz' asia 1.1
-# Elz says "no guarantees"
+# New Zealand
# From Mark Davies (1990-10-03):
# the 1989/90 year was a trial of an extended "daylight saving" period.
# time on both the first Sunday in October and the third Sunday in March.
# As with Australia, we'll assume the tradition is 2:00s, not 2:00.
#
-# From Paul Eggert (1996-11-22):
-# Shanks gives no data for Chatham; usno1989 says it's +12:45,
-# usno1995 says it's +12:45/+13:45, and IATA SSIM (1991/1996)
+# From Paul Eggert (1999-10-29):
+# Shanks gives no time data for Chatham; usno1989 says it's +12:45,
+# usno1995 says it's +12:45/+13:45, and IATA SSIM (1991/1999)
# gives the NZ rules but with transitions at 2:45 local standard time.
-# Guess that they adopted DST in 1990.
+# Guess that they have been in lock-step with NZ since 1990.
###############################################################################
+
# Fiji
-# Howse writes (p 162) that in 1879 the British governor of Fiji
-# enacted an ordinance standardizing the islands on +12:00.
-# Perhaps it didn't take. We go with Shanks's more precise date in 1915.
+# Howse writes (p 153) that in 1879 the British governor of Fiji
+# enacted an ordinance standardizing the islands on Antipodean Time
+# instead of the American system (which was one day behind).
+
+# From Rives McDow (1998-10-08):
+# Fiji will introduce DST effective 0200 local time, 1998-11-01
+# until 0300 local time 1999-02-28. Each year the DST period will
+# be from the first Sunday in November until the last Sunday in February.
+
+# From Paul Eggert (2000-01-08):
+# IATA SSIM (1999-09) says DST ends 0100 local time. Go with McDow.
+
+# From the BBC World Service (1998-10-31 11:32 UTC):
+# The Fijiian government says the main reasons for the time change is to
+# improve productivity and reduce road accidents. But correspondents say it
+# also hopes the move will boost Fiji's ability to compete with other pacific
+# islands in the effort to attract tourists to witness the dawning of the new
+# millenium.
+
+# http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
+# reports that Fiji has discontinued DST.
# Johnston
# Johnston data is from usno1995.
+
# Kiribati
# From Paul Eggert (1996-01-22):
# ``declared it the same day throught the country as of Jan. 1, 1995''
# as part of the competition to be first into the 21st century.
+
# Kwajalein
# In comp.risks 14.87 (26 August 1993), Peter Neumann writes:
# respect to the International Date Line, to rejoin its fellow islands,
# going from 11:59 p.m. Thursday to 12:00 m. Saturday in a blink.
+
# N Mariana Is, Guam
-# Howse writes (p 162) ``The Spaniards, on the other hand, reached the
+# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
# Philippines and the Ladrones from America,'' and implies that the Ladrones
# (now called the Marianas) kept American date for quite some time.
-# Ignore this for now, as we have no hard data. See also Asia/Manila.
+# For now, we assume the Ladrones switched at the same time as the Philippines;
+# see Asia/Manila.
+
+# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time,
+# under the name "Chamorro Standard Time". There is no official abbreviation,
+# but Congressman Robert A. Underwood, author of the bill that became law,
+# wrote in a press release (2000-12-27) that he will seek the use of "ChST".
+
# Micronesia
# ``I am certain, having lived there for the past decade, that "Truk"
# (now properly known as Chuuk) ... is in the time zone GMT+10.''
#
-# Shanks writes that Truk switched from GMT+10 to GMT+11 on 1978-10-01;
+# Shanks writes that Truk switched from UTC+10 to UTC+11 on 1978-10-01;
# ignore this for now.
+# From Paul Eggert (1999-10-29):
+# The Federated States of Micronesia Visitors Board writes in
+# <a href="http://www.fsmgov.org/info/clocks.html">
+# The Federated States of Micronesia - Visitor Information
+# </a> (1999-01-26)
+# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11.
+# We don't know when Kosrae switched from UTC+12; assume January 1 for now.
+
+
+# Pitcairn
+
+# From Rives McDow (1999-11-08):
+# A Proclamation was signed by the Governor of Pitcairn on the 27th March 1998
+# with regard to Pitcairn Standard Time. The Proclamation is as follows.
+#
+# The local time for general purposes in the Islands shall be
+# Co-ordinated Universal time minus 8 hours and shall be known
+# as Pitcairn Standard Time.
+#
+# ... I have also seen Pitcairn listed as UTC minus 9 hours in several
+# references, and can only assume that this was an error in interpretation
+# somehow in light of this proclamation.
+
+# From Rives McDow (1999-11-09):
+# The Proclamation regarding Pitcairn time came into effect on 27 April 1998
+# ... at midnight.
+
+# From Howie Phelps (1999-11-10), who talked to a Pitcairner via shortwave:
+# Betty Christian told me yesterday that their local time is the same as
+# Pacific Standard Time. They used to be 1/2 hour different from us here in
+# Sacramento but it was changed a couple of years ago.
+
+
# Samoa
-# Howse writes that in 1879 the King of Samoa decided to change
+# Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
+# that in 1879 the King of Samoa decided to change
# ``the date in his kingdom from the Antipodean to the American system,
# ordaining -- by a masterpiece of diplomatic flattery -- that
# the Fourth of July should be celebrated twice in that year.''
+
# Tonga
# From Paul Eggert (1996-01-22):
# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
# Since Kiribati has moved the Date Line it's not clear what Tonga will do.
+
+# Don Mundell writes in the 1997-02-20 Tonga Chronicle
+# <a href="http://www.tongatapu.net.to/tonga/homeland/timebegins.htm">
+# How Tonga became `The Land where Time Begins'
+# </a>:
+
+# Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
+# 12 hours and 20 minutes ahead of GMT. When New Zealand adjusted its
+# standard time in 1940s, Tonga had the choice of subtracting from its
+# local time to come on the same standard time as New Zealand or of
+# advancing its time to maintain the differential of 13 degrees
+# (approximately 50 minutes ahead of New Zealand time).
+#
+# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
+# Tungi, preferred to ensure Tonga's title as the land where time
+# begins, the Legislative Assembly approved the latter change.
+#
+# But some of the older, more conservative members from the outer
+# islands objected. "If at midnight on Dec. 31, we move ahead 40
+# minutes, as your Royal Highness wishes, what becomes of the 40
+# minutes we have lost?"
+#
+# The Crown Prince, presented an unanswerable argument: "Remember that
+# on the World Day of Prayer, you would be the first people on Earth
+# to say your prayers in the morning."
+
+# From Paul Eggert (1999-08-12):
+# Shanks says the transition was on 1968-10-01; go with Mundell.
+
+# From Eric Ulevik (1999-05-03):
+# Tonga's director of tourism, who is also secretary of the National Millenium
+# Committee, has a plan to get Tonga back in front.
+# He has proposed a one-off move to tropical daylight saving for Tonga from
+# October to March, which has won approval in principle from the Tongan
+# Government.
+
+# From Steffen Thorsen [straen@thorsen.priv.no] (1999-09-09):
+# * Tonga will introduce DST in November
+#
+# I was given this link by John Letts <johnletts@earthlink.net>:
+# <a hef="http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm">
+# http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
+# </a>
+#
+# I have not been able to find exact dates for the transition in November
+# yet. By reading this article it seems like Fiji will be 14 hours ahead
+# of UTC as well, but as far as I know Fiji will only be 13 hours ahead
+# (12 + 1 hour DST).
+
+# From Arthur David Olson [arthur_david_olson@nih.gov] (1999-09-20):
+# According to <a href="http://www.tongaonline.com/news/sept1799.html>
+# http://www.tongaonline.com/news/sept1799.html
+# </a>:
+# "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
+# and annually thereafter from the first Saturday in October through the
+# third Saturday of April. Under the system approved by Privy Council on
+# Sept. 10, clocks must be turned ahead one hour on the opening day and
+# set back an hour on the closing date."
+# Alas, no indication of the time of day.
+
+# From Rives McDow (1999-10-06):
+# Tonga started its Daylight Saving on Saturday morning October 2nd at 0200am.
+# Daylight Saving ends on April 16 at 0300am which is Sunday morning.
+
+# From Steffen Thorsen (2000-10-31):
+# Back in March I found a notice on the website http://www.tongaonline.com
+# that Tonga changed back to standard time one month early, on March 19
+# instead of the original reported date April 16. Unfortunately, the article
+# is no longer available on the site, and I did not make a copy of the
+# text, and I have forgotten to report it here.
+# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
+
+# From Rives McDow (2000-12-01):
+# Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
+
+###############################################################################
+
+# The International Date Line
+
+# From Gwillim Law (2000-01-03):
+#
+# The International Date Line is not defined by any international standard,
+# convention, or treaty. Mapmakers are free to draw it as they please.
+# Reputable mapmakers will simply ensure that every point of land appears on
+# the correct side of the IDL, according to the date legally observed there.
+#
+# When Kiribati adopted a uniform date in 1995, thereby moving the Phoenix and
+# Line Islands to the west side of the IDL (or, if you prefer, moving the IDL
+# to the east side of the Phoenix and Line Islands), I suppose that most
+# mapmakers redrew the IDL following the boundary of Kiribati. Even that line
+# has a rather arbitrary nature. The straight-line boundaries between Pacific
+# island nations that are shown on many maps are based on an international
+# convention, but are not legally binding national borders.
+#
+# An Anglo-French Conference on Time-Keeping at Sea (June, 1917) agreed that
+# legal time on the high seas would be zone time, i.e., the standard time at
+# the nearest meridian that is a multiple of fifteen degrees. The date is
+# governed by the IDL; therefore, even on the high seas, there may be some
+# places as late as fourteen hours later than UTC. And, since the IDL is not
+# an international standard, there are some places on the high seas where the
+# correct date is ambiguous.
-# $OpenBSD: backward,v 1.4 1997/01/14 04:36:50 millert Exp $
-# @(#)backward 7.13
+# @(#)backward 7.20
# This file provides links between current names for time zones
# and their old names. Many names changed in late 1993.
Link America/Adak America/Atka
+Link America/Tijuana America/Ensenada
Link America/Indianapolis America/Fort_Wayne
Link America/Indiana/Knox America/Knox_IN
+Link America/Rio_Branco America/Porto_Acre
Link America/St_Thomas America/Virgin
+Link Asia/Dhaka Asia/Dacca
+Link Asia/Ashgabat Asia/Ashkhabad
Link Asia/Jerusalem Asia/Tel_Aviv
+Link Asia/Thimphu Asia/Thimbu
+Link Asia/Ulaanbaatar Asia/Ulan_Bator
Link Australia/Sydney Australia/ACT
Link Australia/Sydney Australia/Canberra
Link Australia/Lord_Howe Australia/LHI
Link Africa/Cairo Egypt
Link Europe/Dublin Eire
Link Europe/London GB
-Link Etc/GMT GMT
+Link Europe/London GB-Eire
+Link Europe/Chisinau Europe/Tiraspol
Link Etc/GMT+0 GMT+0
Link Etc/GMT-0 GMT-0
Link Etc/GMT0 GMT0
-# $OpenBSD: etcetera,v 1.3 1997/01/14 04:36:51 millert Exp $
-# @(#)etcetera 7.6
+# @(#)etcetera 7.11
# These entries are mostly present for historical reasons, so that
# people in areas not otherwise covered by the tz files could "zic -l"
Zone Etc/UTC 0 - UTC
Zone Etc/UCT 0 - UCT
+# The following link uses older naming conventions,
+# but it belongs here, not in the file `backward',
+# as functions like gmtime load the "GMT" file to handle leap seconds properly.
+# We want this to work even on installations that omit the other older names.
+Link Etc/GMT GMT
+
Link Etc/UTC Etc/Universal
Link Etc/UTC Etc/Zulu
Link Etc/GMT Etc/GMT+0
Link Etc/GMT Etc/GMT0
-# We use POSIX-style signedness in the names and output,
-# internal-style signedness in the specifications.
-# For example, TZ=Etc/GMT+4 corresponds to 4 hours _behind_ GMT;
-# it is equivalent to TZ=GMT+4, which is implemented directly as per POSIX.
+# We use POSIX-style signs in the Zone names and the output abbreviations,
+# even though this is the opposite of what many people expect.
+# POSIX has positive signs west of Greenwich, but many people expect
+# positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses
+# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
+# (i.e. west of Greenwich) even though many people would expect it to
+# mean 4 hours ahead of UTC (i.e. east of Greenwich).
+#
+# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation
+# (which is not yet supported by the tz code) allows for
+# TZ='<GMT-4>+4'; if you want time zone abbreviations conforming to
+# ISO 8601 you can use TZ='<-0400>+4'. Thus the commonly-expected
+# offset is kept within the angle bracket (and is used for display)
+# while the POSIX sign is kept outside the angle bracket (and is used
+# for calculation).
+#
+# Do not use a TZ setting like TZ='GMT+4', which is four hours behind
+# GMT but uses the completely misleading abbreviation "GMT".
# Earlier incarnations of this package were not POSIX-compliant,
# and had lines such as
-# $OpenBSD: europe,v 1.5 1997/01/14 04:36:52 millert Exp $
-# @(#)europe 7.42
+# @(#)europe 7.78
+
+# $FreeBSD: src/share/zoneinfo/europe,v 1.22 2001/04/06 16:46:52 wollman Exp $
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-10-29):
# A good source for time zone historical data outside the U.S. is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# of the IATA's data after 1990.
#
-# Except where otherwise noted, Shanks is the source for entries through 1990,
-# and IATA SSIM is the source for entries after 1990.
+# Except where otherwise noted, Shanks is the source for entries through 1991,
+# and IATA SSIM is the source for entries afterwards.
+#
+# Other sources occasionally used include:
#
-# Another source occasionally used is Edward W. Whitman, World Time Differences,
-# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
-# I found in the UCLA library.
+# Edward W. Whitman, World Time Differences,
+# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
+# which I found in the UCLA library.
+#
+# Brazil's Departamento Servico da Hora (DSH),
+# <a href="http://pcdsh01.on.br/HISTHV.htm">
+# History of Summer Time
+# </a> (1998-09-21, in Portuguese)
+
#
# I invented the abbreviations marked `*' in the following table;
# the rest are from earlier versions of this file, or from other sources.
# 2:00 EET EEST Eastern Europe
# 3:00 MSK MSD Moscow
#
-# See the `africa' file for time zone naming and abbreviation conventions.
-#
# A reliable and entertaining source about time zones, especially in Britain,
-# is Derek Howse, Greenwich time and the discovery of the longitude,
-# Oxford University Press (1980).
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
# From Peter Ilieve <peter@memex.co.uk> (1994-12-04),
# The original six [EU members]: Belgium, France, (West) Germany, Italy,
###############################################################################
-# United Kingdom
-# The UK and its colonies adopted the Gregorian calendar on 1752-09-14.
+# Britain (United Kingdom) and Ireland (Eire)
# From Peter Ilieve <peter@memex.co.uk> (1994-07-06):
#
# Howse writes that Britain was the first country to use standard time.
# The railways cared most about the inconsistencies of local mean time,
# and it was they who forced a uniform time on the country.
-# The original idea was credited to Dr. William Hyde Wollaston (1766-1828);
-# it was popularized in 1840 by Capt. Basil Hall, RN (1788-1844),
-# famed explorer and former Commissioner for Longitude.
+# The original idea was credited to Dr. William Hyde Wollaston (1766-1828)
+# and was popularized by Abraham Follett Osler (1808-1903).
# The first railway to adopt London time was the Great Western Railway
# in November 1840; other railways followed suit, and by 1847 most
-# (though not all) railways used London time. On 1847 Sep 22 the
+# (though not all) railways used London time. On 1847-09-22 the
# Railway Clearing House, an industry standards body, recommended that GMT be
-# adopted at all stations; the January 1848 Bradshaw's lists most major
+# adopted at all stations as soon as the General Post Office permitted it.
+# The transition occurred on 12-01 for the L&NW, the Caledonian,
+# and presumably other railways; the January 1848 Bradshaw's lists many
# railways as using GMT. By 1855 the vast majority of public
-# clocks in Britain were set to GMT (though some, like the Great Clock
-# in Tom Tower at Christ Church, Oxford, were fitted with two minute hands,
+# clocks in Britain were set to GMT (though some, like the great clock
+# on Tom Tower at Christ Church, Oxford, were fitted with two minute hands,
# one for local time and one for GMT). The last major holdout was the legal
# system, which stubbornly stuck to local time for many years, leading
# to oddities like polls opening at 08:13 and closing at 16:13.
# The legal system finally switched to GMT when the Statutes (Definition
-# of Time) Act took effect; it received the Royal Assent on 1880 Aug 2.
+# of Time) Act took effect; it received the Royal Assent on 1880-08-02.
#
# In the tables below, we condense this complicated story into a single
-# transition date for London, namely 1847 Sep 22. We don't know as much
-# about Dublin, so we use 1880 Aug 2, the legal transition time.
+# transition date for London, namely 1847-12-01. We don't know as much
+# about Dublin, so we use 1880-08-02, the legal transition time.
-# From Paul Eggert (1996-06-12):
+# From Paul Eggert (1999-01-30):
# Summer Time was first seriously proposed by William Willett (1857-1915),
-# a London builder who circulated a pamphlet ``Waste of Daylight'' (1907)
+# a London builder and member of the Royal Astronomical Society
+# who circulated a pamphlet ``The Waste of Daylight'' (1907)
# that proposed advancing clocks 20 minutes on each of four Sundays in April,
# and retarding them by the same amount on four Sundays in September.
# A bill was drafted in 1909 and introduced in Parliament several times,
# but it met with ridicule and opposition, especially from farming interests.
# One-hour Summer Time was eventually adopted as a wartime measure in 1916.
+# See:
+# <a href="http://www.the-times.co.uk/news/pages/tim/2000/05/18/x-timcrtcrt01011.html">
+# Summer Time Arrives Early, The Times (2000-05-18)
+# </a>
+# A monument was erected in 1927 to Willett, in an open space in a 45-acre wood
+# near Chiselhurst, Kent that was purchased by popular subscription and open
+# to the public.
# From Paul Eggert (1996-09-03):
# The OED Supplement says that the English originally said ``Daylight Saving''
# If you can predict what Parliament will do, you should be in
# politics making a fortune, not computing.
-# From Peter Ilieve <peter@memex.co.uk> (1993-09-03):
-#
-# Our Government...couldn't...make a decision after the 1989 consultation
-# exercise about the UK changing its timezone so it just let things drift
-# (different from deciding to keep the status quo). According to the
-# Summer Time Order 1992 (SI 1992/1729) the dates of Summer Time for 1993
-# and 1994 are:
-# Start End
-# 1993 28 March 24 October
-# 1994 27 March 23 October
-# All start and end times are at 01:00 GMT.
-#
-# There [was] an error in your tables for the start and end times prior to 1981.
-# The UK always used to change at 02:00 GMT. In 1981 it changed to 01:00 GMT
-# as a part of EC harmonisation and has remained at that time since.
-#
-# I have found the default algorithm for UK Summer Time, it is in the
-# Summer Time Act 1972. Section 1 states that in the absence of an Order
-# in Council Summer Time starts at 02:00 GMT on the morning of the day
-# after the third Saturday in March, unless that day is Easter Day, in
-# which case it is the morning of the day after the second Saturday.
-# It ends at 02:00 GMT on the morning of the day after the fourth Saturday
-# in October. (All the redundant `morning of the day ...' is in the Act.)
-# This is only of passing interest now as it will always be overridden by
-# an Order in Council (a Statutory Instrument, the SI thing mentioned above)
-# to specify the EC specified dates.
-
-# From Peter Ilieve <peter@memex.co.uk> (1993-10-18):
-#
-# My contact in the Ministry of Defence Public Relations department
-# accepted the challenge of looking into this and produced the following,
-# from Hansard (the official record of the UK Parliament), Oral Answers,
-# 1 March 1945, cols 1559--60:
-#
-# `58. Major Sir Goronwy Owen asked the Secretary of State for the Home
-# Department if he is now able to state the Government's proposals
-# regarding double summer time.
-#
-# [two other similar questions omitted]
-#
-# Mr. H. Morrison: The Government, in reviewing the matter, have
-# considered, [...] the conclusion has been reached that the adoption of
-# double summer time from the beginning of April is essential to the
-# maintenance of the war effort. [...] As 1st April is Easter Sunday,
-# when very early services are held in many churches, it is proposed that
-# double summer time shall start not in the night preceding Easter
-# Sunday, but in the night of Sunday- Monday so that it will operate from
-# Monday, 2nd April.'
-
# From Chris Carrier <72157.3334@CompuServe.COM> (1996-06-14):
# I remember reading in various wartime issues of the London Times the
# acronym BDST for British Double Summer Time. Look for the published
# time of sunrise and sunset in The Times, when BDST was in effect, and
# if you find a zone reference it will say, "All times B.D.S.T."
-# From Peter Ilieve <peter@memex.co.uk> (1993-09-03):
-#
-# > # Current rules
-# > Rule GB-Eire 1981 max - Mar lastSun 1:00s 1:00 BST
-# > Rule GB-Eire 1981 max - Oct Sun>=23 1:00s 0 GMT
-#
-# The ending rule here doesn't match the EC rules, which specify the fourth
-# Sunday in October for the UK and Eire. The `fourth Sunday' rule wasn't
-# followed in 1989, but then the sixth EC directive wasn't in force then
-# and I don't know what previous ones said. 1995 is the next year with
-# the 4th Sun on 22 Oct, but that year isn't covered by the UK Summer Time
-# Order or the sixth EC directive. Your Oct Sun>=23 rule matches history
-# and with things only announced for 2 years or so in advance who knows
-# what will happen.
-#
-# There are renewed rumours that the Government here will make another
-# attempt at resolving this issue, which is what prompted me to start
-# asking the Home Office and the EC about it again. The EC categorically
-# state they are not asking anybody to change timezone, they only want
-# common start/end dates. The UK Govt. seem to want to change our zone
-# and blame the resulting fuss on the EC. Me, I think we should scrap
-# summer time completely, noon is when the Sun is overhead, and that should
-# be the end of it.
-
-# From Peter Ilieve <peter@memex.co.uk> (1993-10-22):
-#
-# I now have the text of the Summer Time Act 1916, the granddaddy of them all.
-# It is headed: `An Act to provide for the Time in Great Britain and Ireland
-# being in advance of Greenwich and Dublin mean time respectively in the
-# summer months'.
-#
-# It specifies 21 May and 1 October for 1916 (both at 02:00 GMT) and whatever
-# dates an Order in Council may specify for subsequent years.
-#
-# Section 4 states: `This act shall apply to Ireland in like manner as it
-# applies to Great Britain, with the substitution however of references
-# to Dublin mean time for references to Greenwich mean time.'
-#
-# Lorna, my learned legal friend who supplied it, also offers this quote
-# from Halsbury's Statutes on the extent of Acts:
-#
-# `An Act of the United Kingdom Parliament is to be construed prima facie
-# to apply to the whole of the United Kingdom and not to any place outside.
-# [...] The expression "United Kingdom" for this purpose includes (since
-# 1922) Great Britain (ie. England, Wales and Scotland) and Northern Ireland,
-# but it does not include the Channel Islands or the Isle of Man.'
-#
-# She goes on to say the seminal event of 1922 was the establishment of
-# the Irish Free State, now called Eire.
-#
-# The Act doesn't say anything about Wales (or Scotland) so I would assert
-# that Shanks is wrong here. I would like to know why he thinks Wales
-# was different.
-#
-# It also confirms the fact that Ireland followed Dublin time back then,
-# and 25 minutes behind Greenwich, as Shanks has it, would be correct.
-
-# From Peter Ilieve <peter@memex.co.uk> (1993-10-28):
-#
-# I now have before me, thanks to my learned legal friend Lorna, the text of
-# the Time (Ireland) Act 1916.
-#
-# It says that as from 2 AM Dublin Mean Time on 1 October 1916 the time
-# for general purposes in Ireland shall be the same as the rest of Great
-# Britain (ie. GMT with the Summer Time periods specified by the Summer Time
-# Act 1916).... As Ireland was behind GMT/BST at 02:00 DMT on 1 Oct GB would
-# have already put the clocks back. Using DST as Dublin Summer Time the
-# sequence would have been:
-# Dublin London
-# 02:34 DST 02:59 BST
-# 02:35 DST 02:00 GMT
-# 02:59 DST 02:24 GMT
-# 02:25 GMT 02:25 GMT
-# with the transition 03:00 DST -> 02:00 DMT -> 02:25 GMT all at once.
-#
-# In a table of repeals in the Schedule to the Act it mentions the
-# Statutes (Definition of Time) Act 1880. This is presumably the source
-# of the 1880 date in Shanks. The little bit of it that is repealed
-# also refers solely to Ireland and Dublin Mean Time.
-
-# From Peter Ilieve <peter@memex.co.uk> (1993-10-29):
-#
-# My case is that, with the sole exception of Ireland in 1916 using Dublin
-# Mean Time, Summer Time has been uniform throughout the United Kingdom
-# ever since it first started in 1916.
-#
-# The United Kingdom is England, Wales and Scotland plus all of Ireland from
-# 1916 up to and including 1921, or plus Northern Ireland from 1922 to date.
-#
-# The dates used are those specified in the table in Summer Time: A Consultation
-# Document (Cm 722, 1989) that are now included in the europe file, with a
-# change to a single date, the start in 1924. I made a typo in my 1989 mail
-# and the table itself is also wrong. The correct date is 13 April.
-# The times were 02:00 GMT up to and including 1980, 01:00 GMT from 1981 on,
-# except for wartime double summer time.
-#
-# As evidence I would cite:
-#
-# - The Summer Time Act, 1916.
-#
-# This specifically states that it applies to Ireland, specifies dates of
-# 21 May and 1 October and times of 02:00, and says that in Ireland the
-# times relate to Dublin mean time. It specifies an offset of 1 hour.
-#
-# - The Time (Ireland) Act, 1916
-#
-# This abolishes Dublin mean time on 02:00 DMT 1 October 1916.
-# It repeals that section of the Statutes (Definition of Time) Act, 1880
-# that specifies DMT. It is therefore a safe bet that DMT existed at least
-# from 1880 and was the only alternative standard time in the UK.
-#
-# - The Summer Time Act, 1922
-#
-# This specifies an offset of 1 hour and dates of the day after the third
-# Saturday in April, unless that be Easter, in which case it is the day after
-# the second Saturday, and the day after the third Saturday in September.
-# The time is 02:00 GMT. It applied in 1922 and 1923, and longer if Parliament
-# so approved.
-#
-# It specifically states that it applies to Northern Ireland, the Channel
-# Islands, and the Isle of Man.
-#
-# - The Summer Time Act, 1925
-#
-# This makes the 1922 Act permanent, with a change to the end date to the
-# day after the first Saturday in October. It says nothing about extent,
-# so that part of the 1922 Act will still apply.
-#
-# - The Defence (Summer Time) Regulations, 1939, SR&O 1939 No. 1379
-# [SR&O == Statutory Regulation and Order]
-#
-# These were made under the Emergency Powers (Defence) Act, 1939.
-# It changes the end date to be the day after the third Saturday in November.
-# It makes consequential changes to some vehicle lighting legislation,
-# which includes the Motor Vehicles and Road Traffic (Northern Ireland) Act,
-# 1934, so it seems clear it applies in Northern Ireland.
-#
-# - An Order in Council amending the The Defence (Summer Time) Regulations,
-# 1939, SR&O 1940 No. 1883
-#
-# This continues summer time throughout the year after it starts in 1940.
-# It says nothing about extent and has no consequential changes.
-#
-# - An Order in Council amending the The Defence (Summer Time) Regulations,
-# 1939, SR&O 1941 No. 476
-#
-# This introduces double summer time, starting at 01:00 GMT on the day after
-# the first Saturday in May and ending at 01:00 GMT on the day after the
-# second Saturday in August, offset another hour from normal summer time,
-# which continues throughout the rest of the year. It goes on a lot about
-# consequential changes to agricultural wages legislation, and says in part
-# `... and in its application to Northern Ireland have effect as
-# if for the references to the Agricultural Wages (Regulation) Acts, 1924 and
-# 1940, there were substituted references to the Agricultural Wages (Regulation)
-# Acts (Northern Ireland), 1939 and 1940, ...'. It also has a similar section
-# for Scotland. Both sections substitute the local Agricultural Wages Board
-# for the Agricultural Wages Board for England and Wales, showing that
-# England and Wales were indivisible.
-#
-# - An Order in Council amending the The Defence (Summer Time) Regulations,
-# 1939, SR&O 1942 No. 506
-#
-# This changes the start date of double summer time to the day after the first
-# Saturday in April. It says nothing about extent.
-#
-# - An Order in Council amending the The Defence (Summer Time) Regulations,
-# 1939, SR&O 1944 No. 932
-#
-# This changed the end date of double summer time to 17 September 1944.
-# (I don't have the text of this, just a note of what it did, the text almost
-# certainly had the `day after the nth Saturday' form.)
-#
-# (I am missing whatever regulations there were to change things in 1945
-# and the Summer Time Act, 1947.)
-#
-# - The British Standard Time Act, 1968
-#
-# This came into force on 27 October 1968 and continued summer time throughout
-# the year as an experiment until it expired on 31 October 1971.
-# There was no double summer time so we didn't have to change the clocks at all.
-# It specifically said it applied to Northern Ireland. It also said it
-# applied to Jersey, Guernsey and the Isle of Man unless they passed
-# measures saying it didn't.
-#
-# - The Manx Time Act, 1968
-#
-# This is an Act of Tynwald (the Isle of Man Parliament) that said that
-# henceforth Manx time would be the same as the time in Great Britain.
-#
-# - The Summer Time Act, 1972
-#
-# This specified a reversion to normal summer time behaviour with a start
-# date of the day after the third Saturday in March, unless that is Easter,
-# when it is the day after the second Saturday, and an end date of the day
-# after the fourth Saturday in October. Times are at 02:00 GMT, offset is
-# 1 hour.
-#
-# It has the same wording about extent as the British Standard Time Act, 1968,
-# applying to Northern Ireland unconditionally and to Jersey, Guernsey and the
-# Isle of Man if they don't do something about it.
-#
-# (I am missing various Summer Time Orders that modified the 1972 Act to
-# harmonise with the EC since 1981. The major change is that the time changes
-# to 01:00 GMT.)
-#
-# - The Summer Time Order, 1992, SI 1992/1729 [SI == Statutory Instrument]
-#
-# This specifies dates of:
-# Start End
-# 1993 28 March 24 October
-# 1994 27 March 23 October
-# All start and end times are at 01:00 GMT....
-#
-# - Some text on the extent of Acts, from Halsbury's Statutes
-#
-# `An Act of the United Kingdom Parliament is to be construed prima facie
-# to apply to the whole of the United Kingdom and not to any place outside.
-# [...] The expression "United Kingdom" for this purpose includes (since
-# 1922) Great Britain (ie. England, Wales and Scotland) and Northern Ireland,
-# but it does not include the Channel Islands or the Isle of Man.'
-#
-# So, many of these measures specifically include Northern Ireland,
-# the Channel Islands and the Isle of Man. None of them exclude any
-# part of the UK. The default interpretation of Acts is that they apply
-# throughout the UK.
-#
-# With that, I rest my case Milud :-)
-#
-# Thanks are due to my learned legal friend Lorna Montgomerie, who dug out
-# the dusty old statutes, and to Melanie Allison of the Ministry of Defence,
-# who provided the wartime regulations and a snippet of Hansard explaining
-# why double summer time started on a Monday in 1945 (it was Easter).
-
-# From Peter Ilieve <peter@aldie.co.uk> (1996-05-29):
-# I have now got a copy of the British Standard Time Act 1968.
-# It says (S4(2)) that it expires at 02:00 GMT on 31 October 1971 unless
-# an Order in Council was passed in Parliament to make the Act permanent.
-# No Order was passed, so 02:00 1971-10-31 it is...
-#
-# Interestingly, it says baldly `This Act shall come into force on
-# 27 October 1968', without giving a time. As S1 of the Act merely
-# stated that `The time for general purposes in the United Kingdom
-# (to be known as British standard time) shall be one hour in
-# advance of Greenwich mean time throughout the year; ...' you could
-# possibly argue that the start time of BStandardT was 00:00 1968-10-27,
-# especially as the Act repealed the Summer Time Acts 1916--1947 in toto,
-# thereby destroying the authority of the Summer Time Order specifying
-# summer time in 1968....
-
-# From Peter Ilieve <peter@memex.co.uk> (1993-11-18)
-#
-# Here is a revised version of my tabrules file for the perl script I sent
-# before. I have personally verified the various Orders back to 1953 and
-# all the Acts.
-#
-# There are no changes to the dates we already have.
-#
-# My doubt about an early start in 1967 on 18 Feb was misplaced, the Order
-# does say 18 Feb. This is an interesting case as the first Order gave a
-# different date of 7 April 1967 for the Isle of Man but this was changed
-# before it came into effect by another Order for the Isle of Man alone.
-#
-# I don't think I will be able to find any more of the earlier Orders.
-# The annual volumes for 1949--52 do not contain the various Summer Time
-# Orders. They therefore don't appear in the index. They rate a mention in
-# italics in the numerical list at the start but that is all.
-# I think what happens is that the annual volume is produced well after the
-# end of the year in question, by which time the Summer Time Order is spent.
-# They assume that nobody would ever be stupid enough to want to see it
-# again so they leave it out.
-#
-# It might be a good idea to put this table, or the output of tabscript
-# showing all the moves because of Easter, in the europe file comments in
-# place of my old transcription of the Green Paper table [the UK Government
-# paper "Summer Time: A Consultation Document" (HMSO Cm722 June 1989)].
-#
-# Peter Ilieve peter@memex.co.uk
-#
-#
-# ## control file for tabscript, a program to generate UK summer time dates
-# ## matching the table in Cm 722, the 1989 Green Paper.
-# ## Lines like this are comments.
-# ## Lines with a single # at the start are copied into the output
-# ## Control lines are of the form
-# ## <years> <start date> <end date> <flags> <double start> <double end>
-# ## <years> is either a single year or a hyphen separated range, with --
-# ## also accepted as I use this in TeX a lot.
-# ## <start date> and <end date> are a digit followed bu a month name.
-# ## It is either an nth Saturday or an explicit date, depending on <flags>.
-# ## 0 and/or none are used when there is no date, as during 1968--71.
-# ## <flags> can contain `fixed' to indicate explicit dates and `double'
-# ## to indicate double summer time dates are present.
-# ## At present double requires fixed as well.
-# ## <double start> and <double end> are like the start and end dates, with
-# ## the exception of the 0 and/or none feature.
-#
-# ## Blank lines are also ignored.
-#
-# ## Places where I am uncertain, not having personally verified the dates
-# ## against the Act or Order, are marked ???
-# ## These dates are taken from the Cm 722 table.
-#
-# # Summer Time Act, 1916
-# 1916 21 May 1 October fixed
-#
-# ## I haven't yet looked for Orders for 1916--22 and I doubt I will find them.
-# # unknown Order or Orders ???
-# 1917 8 apr 17 sep fixed
-# 1918 24 mar 30 sep fixed
-# 1919 30 mar 29 sep fixed
-# # end date extended in 1920 from 27 Sep because of coal strike (from Cm 722)
-# 1920 28 mar 25 oct fixed
-# 1921 3 apr 3 oct fixed
-#
-# # Summer Time Act, 1922
-# # came into force 22 July 1922, too late for 1922, so missing Order ???
-# 1922 26 mar 8 oct fixed
-# 1923-1924 3 April 3 September
-#
-# # Summer Time Act, 1925
-# 1925--1938 3 April 1 October
-#
-# # Defence (Summer Time) Regulations, 1939
-# 1939 3 April 3 November
-# # 1940 amendment (SR&O 1940 Nos. 172 & 1883)
-# 1940 4 feb 0 none
-# # 1941 amendment (SR&O 1941 No. 476)
-# 1941 0 none 0 none fixed,double 4 may 10 aug
-# # 1942 amendment (SR&O 1942 No. 506)
-# 1942 0 none 0 none fixed,double 5 apr 9 aug
-# 1943 0 none 0 none fixed,double 4 apr 15 aug
-# # 1944 amendment (SR&O 1944 No. 932)
-# 1944 0 none 0 none fixed,double 2 apr 17 sep
-# # 1945 dates from Hansard, Oral Answers, 1 March 1945
-# 1945 0 none 7 oct fixed,double 2 apr 15 jul
-#
-# # reversion to Summer Time Act, 1925
-# 1946 3 April 1 October
-#
-# # Summer Time Act, 1947
-# # Fixed dates for 1947 only, gives power to have double summer time
-# 1947 16 mar 2 nov fixed,double 13 apr 10 aug
-# ## I can't find any trace of the Order for 1948.
-# # Unknown Order ???
-# 1948 14 mar 31 oct fixed
-# ## I know the numbers for the 1949--52 ones but the text is missing from the
-# ## annual volumes. I also don't know if the 49 Order was for 49 or 50, etc.
-# # Summer Time Order, 1949 (SI1949/373) ???
-# 1949 3 apr 30 oct fixed
-# # Summer Time Order, 1950 (SI1950/518) ???
-# 1950 16 apr 22 oct fixed
-# # Summer Time Order, 1951 (SI1951/430) ???
-# 1951 15 apr 21 oct fixed
-# # Summer Time Order, 1952 (SI1952/451) ???
-# 1952 20 apr 26 oct fixed
-#
-# # reversion to Summer Time Act, 1925
-# 1953--1960 3 April 1 October
-#
-# ## All Orders from here on specify fixed dates, not day after nth Sunday
-# ## Start pattern looks like Mar lastSun up to 1963, Mar Sun>=19 up to 1967.
-# ## End pattern looks like Oct Sun>=23 up to 1967.
-# # Summer Time Order, 1961 (SI1961/71)
-# 1961 26 March 29 October fixed
-# # Summer Time (1962) Order, 1961 (SI1961/2465)
-# 1962 25 Mar 28 Oct fixed
-# # Summer Time Order, 1963 (SI1963/81)
-# 1963 31 March 27 October fixed
-# # Summer Time (1964) Order, 1963 (SI1963/2101)
-# 1964 22 March 25 October fixed
-# # Summer Time Order, 1964 (SI1964/1201)
-# 1965 21 Mar 24 Oct fixed
-# 1966 20 Mar 23 Oct fixed
-# 1967 19 Mar 29 Oct fixed
-# # Summer Time Order, 1967 (SI1967/1148)
-# # Specifies different start date of 7 April for Isle of Man
-# # Summer Time Order, 1968 (SI1968/117)
-# # Changes Isle of Man start date to 18 Feb to match rest of UK
-# # British Standard Time Act, 1968
-# 1968 18 feb 0 none fixed
-# 1969--1970 0 none 0 none
-# 1971 0 none 31 oct fixed
-#
-# # Summer Time Act, 1972
-# 1972-1980 3 March 4 October
-#
-# # The pattern here looks like Last Sun in Mar, day after 4th Sat in Oct
-# # First EC Directive ???
-# # Summer Time Order, 1980 (SI1980/1089)
-# 1981 29 Mar 25 Oct fixed
-# 1982 28 Mar 24 Oct fixed
-# # Second EC Directive ???
-# # Summer Time Order, 1982 (SI1982/1673)
-# 1983 27 Mar 23 Oct fixed
-# 1984 25 Mar 28 Oct fixed
-# 1985 31 Mar 27 Oct fixed
-# # Third EC Directive ???
-# # Summer Time Order, 1986 (SI1986/223)
-# 1986 30 Mar 26 Oct fixed
-# 1987 29 Mar 25 Oct fixed
-# 1988 27 Mar 23 Oct fixed
-# # Fourth EC Directive ???
-# # Summer Time Order, 1988 (SI1988/931)
-# 1989 26 Mar 29 Oct fixed
-# # Fifth EC Directive ???
-# # Summer Time Order, 1989 (SI1989/985)
-# 1990 25 Mar 28 Oct fixed
-# 1991 31 Mar 27 Oct fixed
-# 1992 29 Mar 25 Oct fixed
-# # Sixth EC Directive
-# # Summer Time Order, 1992 (SI1992/1729)
-# 1993 28 Mar 24 Oct fixed
-# 1994 27 Mar 23 Oct fixed
-
-# From Peter Ilieve <peter@memex.co.uk> (1994-08-18):
-# I now have the text of the 7th EC directive on summer time arrangements
-# (94/21/EC), which was approved on 30 May....
-# The major changes from existing practice are that 1995 will be the last year
-# that the UK and Eire finish on a different date from everyone else,
-# and the common end date from 1996 onwards will be the last Sunday in October.
-# Year Start End End (UK & Eire, 1995 only)
-# (rule) (last Sun) (last Sun) (4th Sun)
-# 1995 26 March 24 September 22 October
-# 1996 31 March 27 October
-# 1997 30 March 26 October
-#
-# From Peter Ilieve <peter@memex.co.uk> (1994-12-01):
-# The final piece of the legislative jigsaw for summer time in the UK for
-# 1995-97 is now in place. The Summer Time Order 1994 (SI 1994/2798)
-# came into force on 16 November. It restates the dates from the EC
-# seventh Summer Time Directive....
-#
-# From Peter Ilieve <peter@aldie.co.uk> (1996-04-20):
-# Proposals for the eighth directive were supposed to have been produced
-# by the Commission by 1 Jan 96. They have not yet appeared (I asked just
-# before Easter).
-
-# From Peter Ilieve <peter@memex.co.uk> (1994-03-28):
-# The [GB-Eire] end date of 22 October [1995] conflicts with your current rule
-# of Oct Sun>=23, and the historical UK formula of Sun after 4th Sat.
-# The last time 4th Sun and Sun after 4th Sat differed was in 1989,
-# when 29 October was used. That year was covered by a UK Summer Time Order
-# for only a single year and it looks as though there was a matching 4th EC
-# directive for just this year. I don't have the text of the 5th EC
-# directive (for 1990--92) but my guess would be it said 4th Sun.
-# To maintain strict historical accuracy you could start a new UK ending rule
-# of Oct Sun>=22 in 1990.
-
-# From Paul Eggert <eggert@twinsun.com> (1996-06-12):
-#
-# As Ilieve remarks, the date `20 April 1924' in the table of ``Summer Time: A
-# Consultation Document'' (Cm 722, 1989) table is a transcription error;
-# 20 April was an Easter Sunday. Shanks has 13 April, the correct date.
-# Also, the table is not quite right for 1925 through 1938; the correct rules
-# (which Shanks uses) are given in the Summer Time Acts of 1922 and 1925.
-# Shanks and the UK Government paper disagree about the Apr 1956 transition;
-# since we have no other data, and since Shanks was correct in the other
-# points of disagreement about London, we'll believe Shanks for now.
-# Also, for lack of other data, we'll follow Shanks for Eire in 1940-1948.
-#
-# Given Peter Ilieve's comments, the following claims by Shanks are incorrect:
-# * Wales did not switch from GMT to daylight savings time until
+# From Joseph S. Myers (1999-09-02):
+# ... some military cables (WO 219/4100 - this is a copy from the
+# main SHAEF archives held in the US National Archives, SHAEF/5252/8/516)
+# agree that the usage is BDST (this appears in a message dated 17 Feb 1945).
+
+# From Joseph S. Myers (2000-10-03):
+# On 18th April 1941, Sir Stephen Tallents of the BBC wrote to Sir
+# Alexander Maxwell of the Home Office asking whether there was any
+# official designation; the reply of the 21st was that there wasn't
+# but he couldn't think of anything better than the "Double British
+# Summer Time" that the BBC had been using informally.
+# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
+# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
+
+# From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
+# [N]o official designation has as far as I know been adopted for the time
+# which is to be introduced in May....
+# I cannot think of anything better than "Double British Summer Time"
+# which could not be said to run counter to any official description.
+
+# From Paul Eggert (2000-10-02):
+# Howse writes (p 157) `DBST' too, but `BDST' seems to have been common
+# and follows the more usual convention of putting the location name first,
+# so we use `BDST'.
+
+# Peter Ilieve <peter@aldie.co.uk> (1998-04-19) described at length
+# the history of summer time legislation in the United Kingdom.
+# Since 1998 Joseph S. Myers <jsm28@cam.ac.uk> has been updating
+# and extending this list, which can be found in
+# <a href="http://student.cusu.cam.ac.uk/~jsm28/british-time/">
+# History of legal time in Britain
+# </a> (2000-02-12).
+
+# From Joseph S. Myers <jsm28@cam.ac.uk> (1998-01-06):
+#
+# The legal time in the UK outside of summer time is definitely GMT, not UTC;
+# see Lord Tanlaw's speech
+# <a href="http://www.parliament.the-stationery-office.co.uk/pa/ld199697/ldhansrd/pdvn/lds97/text/70611-20.htm#70611-20_head0">
+# (Lords Hansard 11 June 1997 columns 964 to 976)
+# </a>.
+
+# From Paul Eggert (2000-02-17):
+#
+# For lack of other data, we'll follow Shanks for Eire in 1940-1948.
+#
+# Given Ilieve and Myers's data, the following claims by Shanks are incorrect:
+# * Wales did not switch from GMT to daylight saving time until
# 1921 Apr 3, when they began to conform with the rest of Great Britain.
# Actually, Wales was identical after 1880.
# * Eire had two transitions on 1916 Oct 1.
# It actually just had one transition.
-# * Northern Ireland used single daylight savings time throughout WW II.
+# * Northern Ireland used single daylight saving time throughout WW II.
# Actually, it conformed to Britain.
# * GB-Eire changed standard time to 1 hour ahead of GMT on 1968-02-18.
# Actually, that date saw the usual switch to summer time.
# Standard time was not changed until 1968-10-27 (the clocks didn't change).
#
-# The following claims by Shanks are possible though doubtful;
-# we'll ignore them for now.
+# Here is another incorrect claim by Shanks:
# * Jersey, Guernsey, and the Isle of Man did not switch from GMT
-# to daylight savings time until 1921 Apr 3, when they began to
+# to daylight saving time until 1921 Apr 3, when they began to
# conform with Great Britain.
+# S.R.&O. 1916, No. 382 and HO 45/10811/312364 (quoted above) say otherwise.
+#
+# The following claim by Shanks is possible though doubtful;
+# we'll ignore it for now.
# * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
#
#
# Whitman says Dublin Mean Time was -0:25:21, which is more precise than Shanks.
+# From Paul Eggert (1999-03-28):
+# Clive Feather (<news:859845706.26043.0@office.demon.net>, 1997-03-31)
+# reports that Folkestone (Cheriton) Shuttle Terminal uses Concession Time
+# (CT), equivalent to French civil time.
+# Julian Hill (<news:36118128.5A14@virgin.net>, 1998-09-30) reports that
+# trains between Dollands Moor (the freight facility next door)
+# and Frethun run in CT.
+# My admittedly uninformed guess is that the terminal has two authorities,
+# the French concession operators and the British civil authorities,
+# and that the time depends on who you're talking to.
+# If, say, the British police were called to the station for some reason,
+# I would expect the official police report to use GMT/BST and not CET/CEST.
+# This is a borderline case, but for now let's stick to GMT/BST.
+
# From an anonymous contributor (1996-06-02):
# The law governing time in Ireland is under Statutory Instrument SI 395/94,
# which gives force to European Union 7th Council Directive # 94/21/EC.
# "Irish Summer Time", abbreviated to "IST".
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-# 1916 to 1925--irregular
+# Summer Time Act, 1916
Rule GB-Eire 1916 only - May 21 2:00s 1:00 BST
Rule GB-Eire 1916 only - Oct 1 2:00s 0 GMT
+# S.R.&O. 1917, No. 358
Rule GB-Eire 1917 only - Apr 8 2:00s 1:00 BST
Rule GB-Eire 1917 only - Sep 17 2:00s 0 GMT
+# S.R.&O. 1918, No. 274
Rule GB-Eire 1918 only - Mar 24 2:00s 1:00 BST
Rule GB-Eire 1918 only - Sep 30 2:00s 0 GMT
+# S.R.&O. 1919, No. 297
Rule GB-Eire 1919 only - Mar 30 2:00s 1:00 BST
Rule GB-Eire 1919 only - Sep 29 2:00s 0 GMT
+# S.R.&O. 1920, No. 458
Rule GB-Eire 1920 only - Mar 28 2:00s 1:00 BST
+# S.R.&O. 1920, No. 1844
Rule GB-Eire 1920 only - Oct 25 2:00s 0 GMT
+# S.R.&O. 1921, No. 363
Rule GB-Eire 1921 only - Apr 3 2:00s 1:00 BST
Rule GB-Eire 1921 only - Oct 3 2:00s 0 GMT
+# S.R.&O. 1922, No. 264
Rule GB-Eire 1922 only - Mar 26 2:00s 1:00 BST
Rule GB-Eire 1922 only - Oct 8 2:00s 0 GMT
+# The Summer Time Act, 1922
Rule GB-Eire 1923 only - Apr Sun>=16 2:00s 1:00 BST
Rule GB-Eire 1923 1924 - Sep Sun>=16 2:00s 0 GMT
-Rule GB-Eire 1924 only - Apr 13 2:00s 1:00 BST
-# 1925 to 1939 start--regular, except for avoiding Easter
+Rule GB-Eire 1924 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1925 1926 - Apr Sun>=16 2:00s 1:00 BST
+# The Summer Time Act, 1925
Rule GB-Eire 1925 1938 - Oct Sun>=2 2:00s 0 GMT
-Rule GB-Eire 1927 only - Apr 10 2:00s 1:00 BST
+Rule GB-Eire 1927 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1928 1929 - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1930 only - Apr 13 2:00s 1:00 BST
+Rule GB-Eire 1930 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1931 1932 - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1933 only - Apr 9 2:00s 1:00 BST
+Rule GB-Eire 1933 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1934 only - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1935 only - Apr 14 2:00s 1:00 BST
+Rule GB-Eire 1935 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1936 1937 - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1938 only - Apr 10 2:00s 1:00 BST
+Rule GB-Eire 1938 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1939 only - Apr Sun>=16 2:00s 1:00 BST
-# 1939 end to 1947--irregular, and with double summer time
-Rule GB-Eire 1939 only - Nov 19 2:00s 0 GMT
-Rule GB-Eire 1940 only - Feb 25 2:00s 1:00 BST
+# S.R.&O. 1939, No. 1379
+Rule GB-Eire 1939 only - Nov Sun>=16 2:00s 0 GMT
+# S.R.&O. 1940, No. 172 and No. 1883
+Rule GB-Eire 1940 only - Feb Sun>=23 2:00s 1:00 BST
+# S.R.&O. 1941, No. 476
Rule GB-Eire 1941 only - May Sun>=2 1:00s 2:00 BDST
Rule GB-Eire 1941 1943 - Aug Sun>=9 1:00s 1:00 BST
+# S.R.&O. 1942, No. 506
Rule GB-Eire 1942 1944 - Apr Sun>=2 1:00s 2:00 BDST
+# S.R.&O. 1944, No. 932
Rule GB-Eire 1944 only - Sep Sun>=16 1:00s 1:00 BST
-# Double daylight starts on a Monday in 1945--see above.
-Rule GB-Eire 1945 only - Apr 2 1:00s 2:00 BDST
-Rule GB-Eire 1945 only - Jul 15 1:00s 1:00 BST
-Rule GB-Eire 1945 only - Oct 7 2:00s 0 GMT
-Rule GB-Eire 1946 only - Apr 14 2:00s 1:00 BST
-Rule GB-Eire 1946 only - Oct 6 2:00s 0 GMT
+# S.R.&O. 1945, No. 312
+Rule GB-Eire 1945 only - Apr Mon>=2 1:00s 2:00 BDST
+Rule GB-Eire 1945 only - Jul Sun>=9 1:00s 1:00 BST
+# S.R.&O. 1945, No. 1208
+Rule GB-Eire 1945 1946 - Oct Sun>=2 2:00s 0 GMT
+Rule GB-Eire 1946 only - Apr Sun>=9 2:00s 1:00 BST
+# The Summer Time Act, 1947
Rule GB-Eire 1947 only - Mar 16 2:00s 1:00 BST
Rule GB-Eire 1947 only - Apr 13 1:00s 2:00 BDST
Rule GB-Eire 1947 only - Aug 10 1:00s 1:00 BST
Rule GB-Eire 1947 only - Nov 2 2:00s 0 GMT
-# So much for double saving time. 1948 and 1949, irregular.
+# Summer Time Order, 1948 (S.I. 1948/495)
Rule GB-Eire 1948 only - Mar 14 2:00s 1:00 BST
-Rule GB-Eire 1948 1949 - Oct lastSun 2:00s 0 GMT
+Rule GB-Eire 1948 only - Oct 31 2:00s 0 GMT
+# Summer Time Order, 1949 (S.I. 1949/373)
Rule GB-Eire 1949 only - Apr 3 2:00s 1:00 BST
-# 1950 through start of 1953, regular.
-Rule GB-Eire 1950 1953 - Apr Sun>=14 2:00s 1:00 BST
+Rule GB-Eire 1949 only - Oct 30 2:00s 0 GMT
+# Summer Time Order, 1950 (S.I. 1950/518)
+# Summer Time Order, 1951 (S.I. 1951/430)
+# Summer Time Order, 1952 (S.I. 1952/451)
+Rule GB-Eire 1950 1952 - Apr Sun>=14 2:00s 1:00 BST
Rule GB-Eire 1950 1952 - Oct Sun>=21 2:00s 0 GMT
-# 1954 to 1980, starting rules
-Rule GB-Eire 1954 only - Apr 11 2:00s 1:00 BST
+# revert to the rules of the Summer Time Act, 1925
+Rule GB-Eire 1953 only - Apr Sun>=16 2:00s 1:00 BST
+Rule GB-Eire 1953 1960 - Oct Sun>=2 2:00s 0 GMT
+Rule GB-Eire 1954 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1955 1956 - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1957 only - Apr 14 2:00s 1:00 BST
+Rule GB-Eire 1957 only - Apr Sun>=9 2:00s 1:00 BST
Rule GB-Eire 1958 1959 - Apr Sun>=16 2:00s 1:00 BST
-Rule GB-Eire 1960 only - Apr 10 2:00s 1:00 BST
+Rule GB-Eire 1960 only - Apr Sun>=9 2:00s 1:00 BST
+# Summer Time Order, 1961 (S.I. 1961/71)
+# Summer Time (1962) Order, 1961 (S.I. 1961/2465)
+# Summer Time Order, 1963 (S.I. 1963/81)
Rule GB-Eire 1961 1963 - Mar lastSun 2:00s 1:00 BST
+Rule GB-Eire 1961 1968 - Oct Sun>=23 2:00s 0 GMT
+# Summer Time (1964) Order, 1963 (S.I. 1963/2101)
+# Summer Time Order, 1964 (S.I. 1964/1201)
+# Summer Time Order, 1967 (S.I. 1967/1148)
Rule GB-Eire 1964 1967 - Mar Sun>=19 2:00s 1:00 BST
+# Summer Time Order, 1968 (S.I. 1968/117)
Rule GB-Eire 1968 only - Feb 18 2:00s 1:00 BST
+# The British Standard Time Act, 1968
+# (no summer time)
+# The Summer Time Act, 1972
Rule GB-Eire 1972 1980 - Mar Sun>=16 2:00s 1:00 BST
-# 1953 to 1980, ending rules
-Rule GB-Eire 1953 1960 - Oct Sun>=1 2:00s 0 GMT
-Rule GB-Eire 1961 1968 - Oct Sun>=23 2:00s 0 GMT
Rule GB-Eire 1972 1980 - Oct Sun>=23 2:00s 0 GMT
-# 1981 on
+# Summer Time Order, 1980 (S.I. 1980/1089)
+# Summer Time Order, 1982 (S.I. 1982/1673)
+# Summer Time Order, 1986 (S.I. 1986/223)
+# Summer Time Order, 1988 (S.I. 1988/931)
Rule GB-Eire 1981 1995 - Mar lastSun 1:00u 1:00 BST
Rule GB-Eire 1981 1989 - Oct Sun>=23 1:00u 0 GMT
+# Summer Time Order, 1989 (S.I. 1989/985)
+# Summer Time Order, 1992 (S.I. 1992/1729)
+# Summer Time Order 1994 (S.I. 1994/2798)
Rule GB-Eire 1990 1995 - Oct Sun>=22 1:00u 0 GMT
+# Summer Time Order 1997 (S.I. 1997/2982)
# See EU for rules starting in 1996.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/London -0:01:15 - LMT 1847 Sep 22
+Zone Europe/London -0:01:15 - LMT 1847 Dec 1
0:00 GB-Eire %s 1968 Oct 27
1:00 - BST 1971 Oct 31 2:00u
0:00 GB-Eire %s 1996
0:00 EU GMT/BST
Zone Europe/Belfast -0:23:40 - LMT 1880 Aug 2
-0:25:21 - DMT 1916 May 21 2:00 # Dublin MT
- -0:25:21 1:00 IST 1916 Oct 1 3:00 # Irish Summer Time
+ -0:25:21 1:00 IST 1916 Oct 1 2:00s # Irish Summer Time
0:00 GB-Eire %s 1968 Oct 27
1:00 - BST 1971 Oct 31 2:00u
0:00 GB-Eire %s 1996
0:00 EU GMT/BST
Zone Europe/Dublin -0:25:21 - LMT 1880 Aug 2
-0:25:21 - DMT 1916 May 21 2:00 # Dublin MT
- -0:25:21 1:00 IST 1916 Oct 1 3:00
+ -0:25:21 1:00 IST 1916 Oct 1 2:00s
0:00 GB-Eire %s 1921 Dec 6 # independence
0:00 GB-Eire GMT/IST 1940 Feb 25 2:00
0:00 1:00 IST 1946 Oct 6 2:00
Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
Rule EU 1996 max - Oct lastSun 1:00u 0 -
+# The most recent directive covers the years starting in 2002. See:
+# <a href="http://europa.eu.int/eur-lex/en/lif/dat/2000/en_300L0084.html"
+# Directive 2000/84/EC of the European Parliament and of the Council
+# of 19 January 2001 on summer-time arrangements.
+# </a>
# W-Eur differs from EU only in that W-Eur uses standard time.
Rule W-Eur 1977 1980 - Apr Sun>=1 1:00s 1:00 S
Rule C-Eur 1917 1918 - Apr Mon>=15 2:00s 1:00 S
Rule C-Eur 1917 1918 - Sep Mon>=15 2:00s 0 -
Rule C-Eur 1940 only - Apr 1 2:00s 1:00 S
-# Whitman says 1941 DST was only from Feb 25 to Oct 5; go with Shanks.
Rule C-Eur 1942 only - Nov 2 2:00s 0 -
Rule C-Eur 1943 only - Mar 29 2:00s 1:00 S
Rule C-Eur 1943 only - Oct 4 2:00s 0 -
Rule Russia 1917 only - Jul 1 23:00 1:00 MST # Moscow Summer Time
Rule Russia 1917 only - Dec 28 0:00 0 MMT # Moscow Mean Time
Rule Russia 1918 only - May 31 22:00 2:00 MDST # Moscow Double Summer Time
-Rule Russia 1918 only - Sep 17 0:00 1:00 MST
+Rule Russia 1918 only - Sep 16 1:00 1:00 MST
Rule Russia 1919 only - May 31 23:00 2:00 MDST
Rule Russia 1919 only - Jul 1 2:00 1:00 S
Rule Russia 1919 only - Aug 16 0:00 0 -
Rule Russia 1921 only - Feb 14 23:00 1:00 S
-# Shanks gives 1921 Mar 21 for the following transition.
-# From Andrey A. Chernov <ache@astral.msk.su> (1993-11-12):
-# My sources says, that it is Mar 20, not 21.
-Rule Russia 1921 only - Mar 20 23:00 2:00 DS
+Rule Russia 1921 only - Mar 20 23:00 2:00 M # Midsummer
Rule Russia 1921 only - Sep 1 0:00 1:00 S
Rule Russia 1921 only - Oct 1 0:00 0 -
+# Act No.925 of the Council of Ministers of the USSR (1980-10-24):
Rule Russia 1981 1984 - Apr 1 0:00 1:00 S
Rule Russia 1981 1983 - Oct 1 0:00 0 -
+# Act No.967 of the Council of Ministers of the USSR (1984-09-13), repeated in
+# Act No.227 of the Council of Ministers of the USSR (1989-03-14):
Rule Russia 1984 1991 - Sep lastSun 2:00s 0 -
Rule Russia 1985 1991 - Mar lastSun 2:00s 1:00 S
+#
Rule Russia 1992 only - Mar lastSat 23:00 1:00 S
Rule Russia 1992 only - Sep lastSat 23:00 0 -
Rule Russia 1993 max - Mar lastSun 2:00s 1:00 S
Rule Albania 1983 only - Apr 18 0:00 1:00 S
Rule Albania 1983 only - Oct 1 0:00 0 -
Rule Albania 1984 only - Apr 1 0:00 1:00 S
-Rule Albania 1984 only - Oct 1 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Tirane 1:19:20 - LMT 1914
1:00 - CET 1940 Jun 16
- 1:00 Albania CE%sT 1985 Mar 31 1:00
- 1:00 W-Eur CE%sT 1991
+ 1:00 Albania CE%sT 1984 Jul
1:00 EU CE%sT
# Andorra
# Belarus
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Minsk 1:50:16 - LMT 1880
- 2:30:20 Russia %s 1919 Jul 1 2:00
- 3:00 Russia MSK/MSD 1922 Oct
+ 1:50 - MMT 1924 May 2 # Minsk Mean Time
2:00 - EET 1930 Jun 21
- 3:00 Russia MSK/MSD 1991 Mar 31 2:00s
+ 3:00 - MSK 1941 Jun 28
+ 1:00 C-Eur CE%sT 1944 Jul 3
+ 3:00 Russia MSK/MSD 1990
+ 3:00 - MSK 1991 Mar 31 2:00s
2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 - EET 1992 Mar 29 0:00
- 2:00 1:00 EEST 1992 Sep 27 0:00
+ 2:00 - EET 1992 Mar 29 0:00s
+ 2:00 1:00 EEST 1992 Sep 27 0:00s
2:00 Russia EE%sT
# Belgium
-# Whitman and Shanks disagree; go with Shanks, usually.
+#
+# From Paul Eggert (1997-07-02):
+# Entries from 1918 through 1991 are taken from:
+# Annuaire de L'Observatoire Royal de Belgique,
+# Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
+# (Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
+# pp 8-9.
+# LMT before 1892 was 0:17:30, according to the official journal of Belgium:
+# Moniteur Belge, Samedi 30 Avril 1892, N.121.
+# Thanks to Pascal Delmoitie <pascal@belnet.be> for these references.
+# The 1918 rules are listed for completeness; they apply to unoccupied Belgium.
+# Assume Brussels switched to WET in 1918 when the armistice took effect.
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-# From Whitman:
+Rule Belgium 1918 only - Mar 9 0:00s 1:00 S
+Rule Belgium 1918 1919 - Oct Sat>=1 23:00s 0 -
Rule Belgium 1919 only - Mar 1 23:00s 1:00 S
-Rule Belgium 1919 only - Oct 4 23:00s 0 -
-# Shanks gives 1920 Feb 14 23:00s; go with Whitman.
-Rule Belgium 1920 1921 - Mar 14 23:00s 1:00 S
+Rule Belgium 1920 only - Feb 14 23:00s 1:00 S
Rule Belgium 1920 only - Oct 23 23:00s 0 -
+Rule Belgium 1921 only - Mar 14 23:00s 1:00 S
Rule Belgium 1921 only - Oct 25 23:00s 0 -
Rule Belgium 1922 only - Mar 25 23:00s 1:00 S
-# Whitman gives 1927 Oct 1 2:00s and 1928 Oct 7 2:00s; go with Shanks.
-Rule Belgium 1922 1928 - Oct Sat>=1 23:00s 0 -
+Rule Belgium 1922 1927 - Oct Sat>=1 23:00s 0 -
Rule Belgium 1923 only - Apr 21 23:00s 1:00 S
Rule Belgium 1924 only - Mar 29 23:00s 1:00 S
Rule Belgium 1925 only - Apr 4 23:00s 1:00 S
+# DSH writes that a royal decree of 1926-02-22 specified the Sun following 3rd
+# Sat in Apr (except if it's Easter, in which case it's one Sunday earlier),
+# to Sun following 1st Sat in Oct, and that a royal decree of 1928-09-15
+# changed the transition times to 02:00 GMT.
Rule Belgium 1926 only - Apr 17 23:00s 1:00 S
Rule Belgium 1927 only - Apr 9 23:00s 1:00 S
Rule Belgium 1928 only - Apr 14 23:00s 1:00 S
+Rule Belgium 1928 1938 - Oct Sun>=2 2:00s 0 -
Rule Belgium 1929 only - Apr 21 2:00s 1:00 S
-Rule Belgium 1929 1938 - Oct Sun>=2 2:00s 0 -
Rule Belgium 1930 only - Apr 13 2:00s 1:00 S
Rule Belgium 1931 only - Apr 19 2:00s 1:00 S
-Rule Belgium 1932 only - Apr 17 2:00s 1:00 S
+Rule Belgium 1932 only - Apr 3 2:00s 1:00 S
Rule Belgium 1933 only - Mar 26 2:00s 1:00 S
Rule Belgium 1934 only - Apr 8 2:00s 1:00 S
Rule Belgium 1935 only - Mar 31 2:00s 1:00 S
Rule Belgium 1936 only - Apr 19 2:00s 1:00 S
-# Whitman says 1937 Apr 18 2:00s; go with Shanks.
Rule Belgium 1937 only - Apr 4 2:00s 1:00 S
-# Whitman says 1938 Apr 10 2:00s; go with Shanks.
Rule Belgium 1938 only - Mar 27 2:00s 1:00 S
Rule Belgium 1939 only - Apr 16 2:00s 1:00 S
Rule Belgium 1939 only - Nov 19 2:00s 0 -
+Rule Belgium 1940 only - Feb 25 2:00s 1:00 S
+Rule Belgium 1944 only - Sep 17 2:00s 0 -
Rule Belgium 1945 only - Apr 2 2:00s 1:00 S
Rule Belgium 1945 only - Sep 16 2:00s 0 -
Rule Belgium 1946 only - May 19 2:00s 1:00 S
Rule Belgium 1946 only - Oct 7 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Brussels 0:17:20 - LMT 1880
- 0:17:20 - BMT 1892 May 1 12:00 # Brussels MT
- 0:00 - WET 1914 Aug 4
- 1:00 C-Eur CE%sT 1919 Mar 1 23:00
- 0:00 Belgium WE%sT 1940 Feb 24 23:00
- 1:00 C-Eur CE%sT 1945 Apr 2 2:00
+Zone Europe/Brussels 0:17:30 - LMT 1880
+ 0:17:30 - BMT 1892 May 1 12:00 # Brussels MT
+ 0:00 - WET 1914 Nov 8
+ 1:00 - CET 1916 May 1 0:00
+ 1:00 C-Eur CE%sT 1918 Nov 11 11:00u
+ 0:00 Belgium WE%sT 1940 May 20 2:00s
+ 1:00 C-Eur CE%sT 1944 Sep 3
1:00 Belgium CE%sT 1977
1:00 EU CE%sT
# Bosnia and Herzegovina
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Sarajevo 1:13:40 - LMT 1884
- 1:00 - CET 1941 Apr 18 23:00
- 1:00 C-Eur CE%sT 1945 May 8 2:00s
- 1:00 1:00 CEST 1945 Sep 16 2:00s
- 1:00 - CET 1983
- 1:00 EU CE%sT
+# see Yugoslavia
# Bulgaria
+#
+# From Plamen Simenov <P.Simeonov@cnsys.bg> via Steffen Thorsen (1999-09-09):
+# A document of Government of Bulgaria (No.94/1997) says:
+# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
+# EETDST --> EET is in 04:00 Local time in last Sunday of October
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Bulg 1979 only - Mar 31 23:00 1:00 S
Rule Bulg 1979 only - Oct 1 1:00 0 -
2:00 - EET 1979 Mar 31 23:00
2:00 Bulg EE%sT 1982 Sep 26 2:00
2:00 C-Eur EE%sT 1991
- 2:00 E-Eur EE%sT
+ 2:00 E-Eur EE%sT 1997
+ 2:00 EU EE%sT
# Croatia
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Zagreb 1:03:52 - LMT 1884
- 1:00 - CET 1941 Apr 18 23:00
- 1:00 C-Eur CE%sT 1945 May 8 2:00s
- 1:00 1:00 CEST 1945 Sep 16 2:00s
- 1:00 - CET 1983
- 1:00 EU CE%sT
+# see Yugosloavia
# Czech Republic
-# Gregorian calendar adopted 1584-01-17.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Czech 1945 only - Apr 8 2:00s 1:00 S
Rule Czech 1945 only - Nov 18 2:00s 0 -
1:00 Czech CE%sT 1979
1:00 EU CE%sT
-# Denmark
-# Gregorian calendar adopted 1700-03-01.
+# Denmark, Faeroe Islands, and Greenland
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Denmark 1916 only - May 14 23:00 1:00 S
Rule Denmark 1916 only - Sep 30 23:00 0 -
Rule Thule 1993 max - Oct lastSun 2:00 0 S
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone America/Scoresbysund -1:29:00 - LMT 1916 Jul 28 # Ittoqqortoormit
+Zone America/Scoresbysund -1:29:00 - LMT 1916 Jul 28 # Ittoqqortoormiit
-2:00 - CGT 1980 Apr 6 2:00
-2:00 C-Eur CG%sT 1981 Mar 29
-1:00 EU EG%sT
Zone America/Godthab -3:26:56 - LMT 1916 Jul 28 # Nuuk
-3:00 - WGT 1980 Apr 6 2:00
-3:00 EU WG%sT
-Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik
+Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik air base
-4:00 Thule A%sT
# Estonia
# A discussion is running about the summer time efficiency and effect on
# human physiology. It seems that Estonia maybe will not change to
# summer time next spring.''
+
+# From Peter Ilieve <peter@aldie.co.uk> (1998-11-04), heavily edited:
+# <a href="http://trip.rk.ee/cgi-bin/thw?${BASE}=akt&${OOHTML}=rtd&TA=1998&TO=1&AN=1390">
+# The 1998-09-22 Estonian time law
+# </a>
+# refers to the Eighth Directive and cites the association agreement between
+# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
+#
+# I also asked [my relative] whether they use any standard abbreviation
+# for their standard and summer times. He says no, they use "suveaeg"
+# (summer time) and "talveaeg" (winter time).
+
+# From <a href="http://www.baltictimes.com/">The Baltic Times</a> (1999-09-09)
+# via Steffen Thorsen:
+# This year will mark the last time Estonia shifts to summer time,
+# a council of the ruling coalition announced Sept. 6....
+# But what this could mean for Estonia's chances of joining the European
+# Union are still unclear. In 1994, the EU declared summer time compulsory
+# for all member states until 2001. Brussels has yet to decide what to do
+# after that.
+
+# From Mart Oruaas (2000-01-29):
+# Regulation no. 301 (1999-10-12) obsoletes previous regulation
+# no. 206 (1998-09-22) and thus sticks Estonia to +02:00 GMT for all
+# the year round. The regulation is effective 1999-11-01.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Tallinn 1:39:00 - LMT 1880
1:39:00 - TMT 1918 Feb # Tallinn Mean Time
1:00 C-Eur CE%sT 1944 Sep 22
3:00 Russia MSK/MSD 1989 Mar 26 2:00s
2:00 1:00 EEST 1989 Sep 24 2:00s
- 2:00 C-Eur EE%sT
+ 2:00 C-Eur EE%sT 1998 Sep 22
+ 2:00 EU EE%sT 1999 Nov 1
+ 2:00 - EET
# Finland
-# See Sweden for when the Gregorian calendar was adopted.
#
# From Hannu Strang <chs@apu.fi> (25 Sep 1994 06:03:37 UTC):
# Well, here in Helsinki we're just changing from summer time to regular one,
2:00 EU EE%sT
# France
-# Gregorian calendar adopted 1582-12-20.
-# French Revolutionary calendar used 1792-09-22 - 1805-12-31.
+
+# From Ciro Discepolo (2000-12-20):
+#
+# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
+# Traditionnelles - Paris 2 books, 1993
+#
+# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
+# Paris, 1991
+#
+# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
+# Guy tredaniel, Paris 1987
+
+
#
# Shanks seems to use `24:00' ambiguously; we resolve it with Whitman.
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule France 1916 only - Jun 14 23:00s 1:00 S
-Rule France 1916 1919 - Oct Sun>=1 0:00 0 -
+Rule France 1916 1919 - Oct Sun>=1 23:00s 0 -
Rule France 1917 only - Mar 24 23:00s 1:00 S
Rule France 1918 only - Mar 9 23:00s 1:00 S
Rule France 1919 only - Mar 1 23:00s 1:00 S
Rule France 1921 only - Mar 14 23:00s 1:00 S
Rule France 1921 only - Oct 25 23:00s 0 -
Rule France 1922 only - Mar 25 23:00s 1:00 S
+# DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st
+# Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions
+# were Apr 12 and Oct 5. Go with Shanks.
Rule France 1922 1938 - Oct Sat>=1 23:00s 0 -
Rule France 1923 only - May 26 23:00s 1:00 S
Rule France 1924 only - Mar 29 23:00s 1:00 S
Rule France 1939 only - Apr 15 23:00s 1:00 S
Rule France 1939 only - Nov 18 23:00s 0 -
Rule France 1940 only - Feb 25 2:00 1:00 S
-# The French rules for 1941-1944 were not used in Paris,
-# but were used in other places (e.g. Monaco).
-Rule France 1941 only - May 5 0:00 2:00 DS
-Rule France 1941 only - Oct 6 1:00 1:00 S
-Rule France 1942 only - Mar 8 0:00 2:00 DS
+# The French rules for 1941-1944 were not used in Paris, but Shanks writes
+# that they were used in Monaco and in many French locations.
+# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
+# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
+# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Decartes,
+# Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
+# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
+# Dole, Morez, St-Claude, and Collognes (Haute-Savioe).
+Rule France 1941 only - May 5 0:00 2:00 M # Midsummer
+# Shanks says this transition occurred at Oct 6 1:00,
+# but go with Denis.Excoffier@ens.fr (1997-12-12),
+# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
+# as saying 5/10/41 22hUT.
+Rule France 1941 only - Oct 6 0:00 1:00 S
+Rule France 1942 only - Mar 9 0:00 2:00 M
Rule France 1942 only - Nov 2 3:00 1:00 S
-Rule France 1943 only - Mar 29 2:00 2:00 DS
-Rule France 1943 only - Nov 4 3:00 1:00 S
-Rule France 1944 only - Apr 3 2:00 2:00 DS
+Rule France 1943 only - Mar 29 2:00 2:00 M
+Rule France 1943 only - Oct 4 3:00 1:00 S
+Rule France 1944 only - Apr 3 2:00 2:00 M
Rule France 1944 only - Oct 8 1:00 1:00 S
-Rule France 1945 only - Apr 2 2:00 2:00 DS
+Rule France 1945 only - Apr 2 2:00 2:00 M
Rule France 1945 only - Sep 16 3:00 0 -
-Rule France 1976 only - Mar 28 2:00s 1:00 S
-Rule France 1976 only - Sep lastSun 2:00s 0 -
+# Shanks gives Mar 28 2:00 and Sep 26 3:00;
+# go with Excoffier's 28/3/76 0hUT and 25/9/76 23hUT.
+Rule France 1976 only - Mar 28 1:00 1:00 S
+Rule France 1976 only - Sep 26 1:00 0 -
# Shanks gives 0:09 for Paris Mean Time, and Whitman gives 0:09:05,
# but Howse quotes the actual French legislation as saying 0:09:21.
# Go with Howse. Howse writes that the time in France was officially based
# on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01
- 0:09:21 - PMT 1911 Mar 11 # Paris Mean Time
- 0:00 France WE%sT 1940 Jun 14
+Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15 0:01
+ 0:09:21 - PMT 1911 Mar 11 0:01 # Paris MT
+# Shanks gives 1940 Jun 14 0:00; go with Excoffier and Le Corre.
+ 0:00 France WE%sT 1940 Jun 14 23:00
+# Le Corre says Paris stuck with occupied-France time after the liberation;
+# go with Shanks.
1:00 C-Eur CE%sT 1944 Aug 25
- 0:00 France WE%sT 1945 Sep 16 3:00
+ 0:00 France WE%sT 1945 Sep 16 3:00
1:00 France CE%sT 1977
1:00 EU CE%sT
# Germany
+# From Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> (1998-09-29):
+# The German time zone web site by the Physikalisch-Technische
+# Bundesanstalt contains DST information back to 1916.
+#
+# <a href="http://www.ptb.de/english/org/4/43/432/lega.htm">
+# Realisation of Legal Time in Germany
+# </a>
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Germany 1945 only - Apr 2 2:00s 1:00 S
-Rule Germany 1945 only - May 24 2:00 2:00 DS
-Rule Germany 1945 only - Sep 24 3:00 1:00 S
+# Shanks says 05-24 2:00 to 09-24 3:00 for DDST; go with the PTB, who quotes
+# the Archiv fuer publizist. Arbeit (Munzinger-Archiv) 652 (Zeitsystem)
+# (1961-11-25), which gives dates only. Guess 3:00 transition times.
+Rule Germany 1945 only - May 31 3:00 2:00 M # Midsummer
+Rule Germany 1945 only - Sep 23 3:00 1:00 S
Rule Germany 1945 only - Nov 18 2:00s 0 -
Rule Germany 1946 only - Apr 14 2:00s 1:00 S
-# Whitman gives 1948 Oct 31; go with Shanks.
-Rule Germany 1946 1949 - Oct Sun>=1 2:00s 0 -
+Rule Germany 1946 only - Oct 7 2:00s 0 -
+Rule Germany 1947 1949 - Oct Sun>=1 2:00s 0 -
Rule Germany 1947 only - Apr 6 2:00s 1:00 S
-Rule Germany 1947 only - May 11 2:00s 2:00 DS
+# The PTB gives 3:00 CET and 3:00 CEST for the midsummer transition times;
+# go with Shanks.
+Rule Germany 1947 only - May 11 2:00s 2:00 M
Rule Germany 1947 only - Jun 29 3:00 1:00 S
Rule Germany 1948 only - Apr 18 2:00s 1:00 S
Rule Germany 1949 only - Apr 10 2:00s 1:00 S
2:00 EU EE%sT
# Hungary
-# Gregorian calendar adopted 1587-11-01.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Hungary 1918 only - Apr 1 3:00 1:00 S
Rule Hungary 1918 only - Sep 29 3:00 0 -
# might be a reference to the Julian calendar as opposed to Gregorian, or it
# might mean something else (???).
#
-# From Paul Eggert <eggert@twinsun.com> (1993-12-09):
+# From Paul Eggert <eggert@twinsun.com> (1999-10-29):
# The Iceland Almanak, Shanks and Whitman disagree on many points.
# We go with the Almanak, except for one claim from Shanks, namely that
-# Reykavik was -1:28 from 1837 to 1908, local mean time before that.
+# Reykavik was 21W57 from 1837 to 1908, local mean time before that.
#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Iceland 1917 1918 - Feb 19 23:00 1:00 S
0:00 - GMT
# Italy
-# Gregorian calendar adopted 1582-10-15.
+#
+# From Paul Eggert (2001-03-06):
+# Sicily and Sardinia each had their own time zones from 1866 to 1893,
+# called ``Palermo Time'' (+0053) and ``Cagliari Time'' (+0038).
+# During World War II, German-controlled Italy used German time.
+# But these events all occurred before the 1970 cutoff,
+# so record only the time in Rome.
#
# From Paul Eggert (1996-05-06):
# For Italian DST we have three sources: Shanks, Whitman, and F. Pollastri
-# <URL:http://pisolo.cstv.to.cnr.it/toi/uk/ienitlt.html> (1996-03-14) (`FP'
-# below), taken from an Italian National Electrotechnical Institute publication.
-# When the three sources disagree, guess who's right, as follows:
+# <a href="http://toi.iriti.cnr.it/uk/ienitlt.html">
+# Day-light Saving Time in Italy (1996-03-14)
+# </a>
+# (`FP' below), taken from an Italian National Electrotechnical Institute
+# publication. When the three sources disagree, guess who's right, as follows:
#
# year FP Shanks (S) Whitman (W) Go with:
# 1916 06-03 06-03 24:00 06-03 00:00 FP & W
Link Europe/Rome Europe/San_Marino
# Latvia
-# From Paul Eggert (1996-11-22):
-# Rules after 1991 are by extension from Shanks. They contradict
-# IATA SSIM (1992/1996), which claims Latvia uses W-Eur rules, but
-# Peter Ilieve's relative writes that Latvia switched in September this year,
-# so we'll assume that the old C-Eur-style rules still apply.
+
+# From Liene Kanepe <Liene_Kanepe@lm.gov.lv> (1998-09-17):
+
+# I asked about this matter Scientific Secretary of the Institute of Astronomy
+# of The University of Latvia Dr. paed Mr. Ilgonis Vilks. I also searched the
+# correct data in juridical acts and I found some juridical documents about
+# changes in the counting of time in Latvia from 1981....
+#
+# Act No.35 of the Council of Ministers of Latvian SSR of 1981-01-22 ...
+# according to the Act No.925 of the Council of Ministers of USSR of 1980-10-24
+# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
+# the hands of the clock 1 hour forward on 1 April at 00:00 (GMT 31 March 21:00)
+# and 1 hour backward on the 1 October at 00:00 (GMT 30 September 20:00).
+#
+# Act No.592 of the Council of Ministers of Latvian SSR of 1984-09-24 ...
+# according to the Act No.967 of the Council of Ministers of USSR of 1984-09-13
+# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
+# the hands of the clock 1 hour forward on the last Sunday of March at 02:00
+# (GMT 23:00 on the previous day) and 1 hour backward on the last Sunday of
+# September at 03:00 (GMT 23:00 on the previous day).
+#
+# Act No.81 of the Council of Ministers of Latvian SSR of 1989-03-22 ...
+# according to the Act No.227 of the Council of Ministers of USSR of 1989-03-14
+# ...: since the last Sunday of March 1989 in Lithuanian SSR, Latvian SSR,
+# Estonian SSR and Kaliningrad region of Russian Federation all year round the
+# time of 2nd time zone (Moscow time minus one hour). On the territory of Latvia
+# transition to summer time is performed on the last Sunday of March at 02:00
+# (GMT 00:00), turning the hands of the clock 1 hour forward. The end of
+# daylight saving time is performed on the last Sunday of September at 03:00
+# (GMT 00:00), turning the hands of the clock 1 hour backward. Exception is
+# 1989-03-26, when we must not turn the hands of the clock....
+#
+# The Regulations of the Cabinet of Ministers of the Republic of Latvia of
+# 1997-01-21 on transition to Summer time ... established the same order of
+# daylight savings time settings as in the States of the European Union.
+
+# From Andrei Ivanov (2000-03-06):
+# This year Latvia will not switch to Daylight Savings Time (as specified in
+# <a href="http://www.lv-laiks.lv/wwwraksti/2000/071072/vd4.htm">
+# The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
+# 29-Feb-2000 (#79)</a>, in Latvian for subscribers only).
+
+# <a href="http://www.rferl.org/newsline/2001/01/3-CEE/cee-030101.html">
+# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
+# </a>
+# The Latvian government on 2 January decided that the country will
+# institute daylight-saving time this spring, LETA reported.
+# Last February the three Baltic states decided not to turn back their
+# clocks one hour in the spring....
+# Minister of Economy Aigars Kalvitis noted that Latvia had too few
+# daylight hours and thus decided to comply with a draft European
+# Commission directive that provides for instituting daylight-saving
+# time in EU countries between 2002 and 2006. The Latvian government
+# urged Lithuania and Estonia to adopt a similar time policy, but it
+# appears that they will not do so....
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Latvia 1992 max - Mar lastSun 2:00s 1:00 S
-Rule Latvia 1992 max - Sep lastSun 2:00s 0 -
+Rule Latvia 1989 1996 - Mar lastSun 2:00s 1:00 S
+Rule Latvia 1989 1996 - Sep lastSun 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Riga 1:36:24 - LMT 1880
1:36:24 - RMT 1918 Apr 15 2:00 #Riga Mean Time
1:36:24 - RMT 1926 May 11
2:00 - EET 1940 Aug 5
3:00 - MSK 1941 Jul
- 1:00 C-Eur CE%sT 1944 Aug 8
- 3:00 Russia MSK/MSD 1991 Mar 31 2:00s
- 2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 Latvia EE%sT
+ 1:00 C-Eur CE%sT 1944 Oct 13
+ 3:00 Russia MSK/MSD 1989 Mar lastSun 2:00s
+ 2:00 1:00 EEST 1989 Sep lastSun 2:00s
+ 2:00 Latvia EE%sT 1997 Jan 21
+ 2:00 EU EE%sT 2000 Feb 29
+ 2:00 - EET 2001
+ 2:00 EU EE%sT
# Liechtenstein
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
1:00 EU CE%sT
# Lithuania
+
+# From Paul Eggert (1996-11-22):
+# IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
+# known to be wrong about Estonia and Latvia, assume it's wrong here too.
+
+# From Marius Gedminas <mgedmin@pub.osf.lt> (1998-08-07):
+# I would like to inform that in this year Lithuanian time zone
+# (Europe/Vilnius) was changed.
+
+# From <a href="http://www.elta.lt/">ELTA</a> No. 972 (2582) (1999-09-29),
+# via Steffen Thorsen:
+# Lithuania has shifted back to the second time zone (GMT plus two hours)
+# to be valid here starting from October 31,
+# as decided by the national government on Wednesday....
+# The Lithuanian government also announced plans to consider a
+# motion to give up shifting to summer time in spring, as it was
+# already done by Estonia.
+
+# From the <a href="http://www.tourism.lt/informa/ff.htm">
+# Fact File, Lithuanian State Department of Tourism
+# </a> (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Vilnius 1:41:16 - LMT 1880
1:24:00 - WMT 1917 # Warsaw Mean Time
1:00 C-Eur CE%sT 1944 Aug
3:00 Russia MSK/MSD 1991 Mar 31 2:00s
2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 C-Eur EE%sT
-# From Paul Eggert (1996-11-22):
-# IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
-# known to be wrong about Estonia and Latvia, assume it's wrong here too.
+ 2:00 C-Eur EE%sT 1998
+ 2:00 - EET 1998 Mar 29 1:00u
+ 1:00 EU CE%sT 1999 Oct 31 1:00u
+ 2:00 - EET
# Luxembourg
# Whitman disagrees with most of these dates in minor ways; go with Shanks.
1:00 EU CE%sT
# Macedonia
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Skopje 1:25:44 - LMT 1884
- 1:00 - CET 1941 Apr 18 23:00
- 1:00 C-Eur CE%sT 1945 May 8 2:00s
- 1:00 1:00 CEST 1945 Sep 16 2:00s
- 1:00 - CET 1983
- 1:00 EU CE%sT
+# see Yugoslavia
# Malta
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
1:00 EU CE%sT
# Moldova
+
+# From Paul Eggert (2001-02-11):
+# A previous version of this database followed Shanks, who writes that
+# Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
+# However, this is most likely an error, as Moldova declared independence
+# on 1991-08-27 (the 1992-01-19 date is that of a Russian decree).
+# In early 1992 there was large-scale interethnic violence in the area
+# and it's possible that some Russophones continued to observe Moscow time.
+# But moldavizolit@tirastel.md and mk@tirastel.md separately reported via
+# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
+# The Tiraspol entry has therefore been removed for now.
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Chisinau 1:55:20 - LMT 1924 May 2
- 2:00 - EET 1930 Jun 21
- 3:00 Russia MSK/MSD 1991 Mar 31 2:00s
- 2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 E-Eur EE%sT
+Zone Europe/Chisinau 1:55:20 - LMT 1880
+ 1:55 - CMT 1918 Feb 15 # Chisinau MT
+ 1:44:24 - BMT 1931 Jul 24 # Bucharest MT
+ 2:00 Romania EE%sT 1940 Aug 15
+ 2:00 1:00 EEST 1941 Jul 17
+ 1:00 C-Eur CE%sT 1944 Aug 24
+ 3:00 Russia MSK/MSD 1990
+ 3:00 - MSK 1990 May 6
+ 2:00 - EET 1991
+ 2:00 Russia EE%sT 1992
+ 2:00 E-Eur EE%sT 1997
+# See Romania commentary for the guessed 1997 transition to EU rules.
+ 2:00 EU EE%sT
# Monaco
# Shanks gives 0:09 for Paris Mean Time; go with Howse's more precise 0:09:21.
# Netherlands
# Howse writes that the Netherlands' railways used GMT between 1892 and 1940,
# but for other purposes the Netherlands used Amsterdam mean time.
+# The data before 1945 is taken from
+# <http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm>.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-# Shanks gives 1916 May 1 0:00 and 1916 Oct 1 0:00; go with Whitman.
-Rule Neth 1916 only - May 1 2:00s 1:00 NST # Netherlands Summer Time
-Rule Neth 1916 only - Oct 2 2:00s 0 AMT # Amsterdam Mean Time
+Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time
+Rule Neth 1916 only - Oct 1 0:00 0 AMT # Amsterdam Mean Time
Rule Neth 1917 only - Apr 16 2:00s 1:00 NST
Rule Neth 1917 only - Sep 17 2:00s 0 AMT
-# Whitman gives 1918 Apr 14, 1918 Oct 31, and 1921 Sep 28; go with Shanks.
Rule Neth 1918 1921 - Apr Mon>=1 2:00s 1:00 NST
-Rule Neth 1918 1921 - Sep Mon>=24 2:00s 0 AMT
-Rule Neth 1922 only - Mar 26 2:00s 1:00 NST
-# Whitman gives 1939 Oct 1; go with Shanks.
+Rule Neth 1918 1921 - Sep lastSun 2:00s 0 AMT
+Rule Neth 1922 only - Mar lastSun 2:00s 1:00 NST
Rule Neth 1922 1936 - Oct Sun>=2 2:00s 0 AMT
-Rule Neth 1923 only - Jun 1 2:00s 1:00 NST
-Rule Neth 1924 only - Mar 30 2:00s 1:00 NST
-# Whitman gives 1925 Apr 5; go with Shanks.
-Rule Neth 1925 only - Jun 5 2:00s 1:00 NST
-# For 1926 through 1930 Whitman gives Apr 15; go with Shanks.
+Rule Neth 1923 only - Jun Fri>=1 2:00s 1:00 NST
+Rule Neth 1924 only - Mar lastSun 2:00s 1:00 NST
+Rule Neth 1925 only - Jun Fri>=1 2:00s 1:00 NST
Rule Neth 1926 1931 - May 15 2:00s 1:00 NST
Rule Neth 1932 only - May 22 2:00s 1:00 NST
Rule Neth 1933 1936 - May 15 2:00s 1:00 NST
Rule Neth 1937 only - May 22 2:00s 1:00 NST
Rule Neth 1937 only - Jul 1 0:00 1:00 S
Rule Neth 1937 1939 - Oct Sun>=2 2:00s 0 -
-# Whitman gives 1939 Apr 15 and 1940 Apr 19; go with Shanks.
Rule Neth 1938 1939 - May 15 2:00s 1:00 S
Rule Neth 1945 only - Apr 2 2:00s 1:00 S
-Rule Neth 1945 only - May 20 2:00s 0 -
-# Before 1937, Shanks says just `0:20'; we use Whitman's more precise figure.
+Rule Neth 1945 only - Sep 16 2:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Amsterdam 0:19:28 - LMT 1892 May
0:19:28 Neth %s 1937 Jul
- 0:20 Neth NE%sT 1940 May 16 0:40
+ 0:20 Neth NE%sT 1940 May 17 0:00
1:00 C-Eur CE%sT 1945 Apr 2 2:00
1:00 Neth CE%sT 1977
1:00 EU CE%sT
# Norway
-# Gregorian calendar adopted 1700-03-01.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# Whitman gives 1916 May 21 - 1916 Oct 21; go with Shanks.
Rule Norway 1916 only - May 22 1:00 1:00 S
Rule Norway 1916 only - Sep 30 0:00 0 -
-# Shanks omits the following transition; go with Whitman.
-Rule Norway 1935 only - Aug 11 0:00 1:00 S
-# Whitman says DST observed until 1942 Nov 1, then 1943 Mar 29 - Oct 4,
-# 1944 Apr 3 - Oct 2, and 1945 Apr 1 - Oct 1; go with Shanks after 1940.
+# Whitman says DST observed 1935-08-11/1942-11-01, then 1943-03-29/10-04,
+# 1944-04-03/10-02, and 1945-04-01/10-01; go with Shanks.
Rule Norway 1945 only - Apr 2 2:00s 1:00 S
Rule Norway 1945 only - Oct 1 2:00s 0 -
Rule Norway 1959 1964 - Mar Sun>=15 2:00s 1:00 S
1:00 C-Eur CE%sT 1945 Apr 2 2:00
1:00 Norway CE%sT 1980
1:00 EU CE%sT
-#
-# Svalbard
+
+# Svalbard & Jan Mayen
Link Europe/Oslo Arctic/Longyearbyen
-#
-# Jan Mayen
# From Whitman:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Atlantic/Jan_Mayen -1:00 - EGT
1:00 Poland CE%sT 1940 Jun 23 2:00
1:00 C-Eur CE%sT 1944 Oct
1:00 Poland CE%sT 1977 Apr 3 1:00
- 1:00 W-Eur CE%sT
+ 1:00 W-Eur CE%sT 1999
# IATA SSIM (1991/1996) gives EU rules, but the _The Warsaw Voice_
-# <URL:http://www.contact.waw.pl/voice/v361/NewsInBrief.shtml>
-# (1995-09-24) says the autumn 1995 switch was at 02:00.
+# <a href="http://www.warsawvoice.com.pl/v361/NewsInBrief.shtml">
+# http://www.warsawvoice.com/pl/v361/NewsInBrief.shtml (1995-09-24)
+# </a>
+# says the autumn 1995 switch was at 02:00.
# Stick with W-Eur for now.
+#
+# From Marcin.Kasperski@softax.com.pl (1999-06-10):
+# According to my colleagues someone recently decided, that Poland would
+# follow European Union regulations, so - I think - the matter is not
+# worth further discussion.
+#
+# From Paul Eggert (1999-06-10):
+# Kasperski also writes that the government futzed with the rules in 1997
+# or 1998 but he doesn't remember the details. Assume they switched to
+# EU rules in 1999.
+ 1:00 EU CE%sT
# Portugal
-# Gregorian calendar adopted 1582-10-15.
#
# From Rui Pedro Salgueiro <rps@inescca.inescc.pt> (1992-11-12):
# Portugal has recently (September, 27) changed timezone
# harmonized with the EU), and that they stayed +0:00 that winter.
#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
+# done every year, depending on what Spain did, because of railroad schedules.
+# Go with Shanks.
Rule Port 1916 only - Jun 17 23:00 1:00 S
# Whitman gives 1916 Oct 31; go with Shanks.
Rule Port 1916 only - Nov 1 1:00 0 -
Rule Port 1940 1941 - Oct 5 23:00s 0 -
Rule Port 1941 only - Apr 5 23:00s 1:00 S
Rule Port 1942 1945 - Mar Sat>=8 23:00s 1:00 S
-Rule Port 1942 only - Apr 25 22:00s 2:00 DS
+Rule Port 1942 only - Apr 25 22:00s 2:00 M # Midsummer
Rule Port 1942 only - Aug 15 22:00s 1:00 S
Rule Port 1942 1945 - Oct Sat>=24 23:00s 0 -
-Rule Port 1943 only - Apr 17 22:00s 2:00 DS
+Rule Port 1943 only - Apr 17 22:00s 2:00 M
Rule Port 1943 1945 - Aug Sat>=25 22:00s 1:00 S
-Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 DS
+Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M
Rule Port 1946 only - Apr Sat>=1 23:00s 1:00 S
Rule Port 1946 only - Oct Sat>=1 23:00s 0 -
Rule Port 1947 1949 - Apr Sun>=1 2:00s 1:00 S
0:00 EU WE%sT
# Romania
+#
+# From Paul Eggert (1999-10-07):
+# <a href="http://www.nineoclock.ro/POL/1778pol.html">
+# Nine O'clock</a> (1998-10-23) reports that the switch occurred at
+# 04:00 local time in fall 1998. For lack of better info,
+# assume that Romania and Moldova switched to EU rules in 1997,
+# the same year as Bulgaria.
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Romania 1932 only - May 21 0:00s 1:00 S
Rule Romania 1932 1939 - Oct Sun>=1 0:00s 0 -
2:00 Romania EE%sT 1981 Mar 29 2:00s
2:00 C-Eur EE%sT 1991
2:00 Romania EE%sT 1994
- 2:00 E-Eur EE%sT
+ 2:00 E-Eur EE%sT 1997
+ 2:00 EU EE%sT
# Russia
-# From Chris Carrier <72157.3334@CompuServe.COM> (1996-12-02):
-# On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar''
-# with 30-day months plus 5 holidays, with a 5-day week.
-# On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
-# Gregorian calendar while retaining the 6-day week; on 1940-06-27 it
-# reverted to the 7-day week. With the 6-day week the usual days
-# off were the 6th, 12th, 18th, 24th and 30th of the month.
-# (Source: Evitiar Zerubavel, _The Seven Day Circle_)
-#
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
-# Except for Moscow after 1919-07-01, I invented the time zone abbreviations,
-# and (unless otherwise specified) guessed what happened after 1991.
+# From Paul Eggert <eggert@twinsun.com> (1999-11-12):
+# Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
# Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
-# are from Andrey A. Chernov. The rest is from Shanks and the IATA.
+# are from Andrey A. Chernov. The rest is from Shanks, except we follow
+# Chernov's report that 1992 DST transitions were Sat 23:00, not Sun 02:00s.
#
# From Andrey A. Chernov <ache@nagual.ru> (1996-10-04):
# `MSK' and `MSD' were born and used initially on Moscow computers with
# Moscow to Irkutsk in 1995, public air and rail transport in Russia ...
# still follows Moscow time, no matter where in Russia it is located.
#
+# For Grozny, Chechnya, we have the following story from
+# John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
+# News--often false--is spread by word of mouth. A rumor that it was
+# time to move the clocks back put this whole city out of sync with
+# the rest of Russia for two weeks--even soldiers stationed here began
+# enforcing curfew at the wrong time.
+#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr
1:00 C-Eur CE%sT 1945
- 2:00 Poland CET 1946
+ 2:00 Poland CE%sT 1946
3:00 Russia MSK/MSD 1991 Mar 31 2:00s
- 2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 - EET 1992 Jan 19 2:00s
- 3:00 Russia MSK/MSD 1994
-# IATA SSIM (1994-02) says Kaliningrad is at UTC+2; guess 1994 change.
2:00 Russia EE%sT
Zone Europe/Moscow 2:30:20 - LMT 1880
- 2:30:20 Russia %s 1919 Jul 1 2:00
+ 2:30 - MMT 1916 Jul 3 # Moscow Mean Time
+ 2:30:48 Russia %s 1919 Jul 1 2:00
3:00 Russia MSK/MSD 1922 Oct
2:00 - EET 1930 Jun 21
3:00 Russia MSK/MSD 1991 Mar 31 2:00s
- 2:00 1:00 EEST 1991 Sep 29 2:00s
- 2:00 - EET 1992 Jan 19 2:00s
+ 2:00 Russia EE%sT 1992 Jan 19 2:00s
3:00 Russia MSK/MSD
-Zone Europe/Samara 3:20:36 - LMT 1924 May 2
- 3:00 - KUYT 1957 Mar # Kuybyshev Time
- 4:00 Russia KUY%sT 1991 Mar 31 2:00s
- 3:00 1:00 KUYST 1991 Sep 29 2:00s
- 3:00 - SAMT 1992 Jan 19 2:00s # Samara Time
- 4:00 Russia SAM%sT
-Zone Asia/Yekaterinburg 4:02:34 - LMT 1924 May 2
- 4:00 - SVET 1957 Mar # Sverdlovsk Time
+Zone Europe/Samara 3:20:36 - LMT 1919 Jul 1 2:00
+ 3:00 - KUYT 1930 Jun 21 # Kuybyshev
+ 4:00 Russia KUY%sT 1989 Mar 26 2:00s
+ 3:00 Russia KUY%sT 1991 Mar 31 2:00s
+ 2:00 Russia KUY%sT 1991 Sep 29 2:00s
+ 3:00 - KUYT 1991 Oct 20 3:00
+ 4:00 Russia SAM%sT # Samara Time
+Zone Asia/Yekaterinburg 4:02:24 - LMT 1919 Jul 15 4:00
+ 4:00 - SVET 1930 Jun 21 # Sverdlovsk Time
5:00 Russia SVE%sT 1991 Mar 31 2:00s
- 4:00 1:00 SVEST 1991 Sep 29 2:00s
- 4:00 - SVET 1992 Jan 19 2:00s
+ 4:00 Russia SVE%sT 1992 Jan 19 2:00s
5:00 Russia YEK%sT # Yekaterinburg Time
-Zone Asia/Omsk 4:53:36 - LMT 1924 May 2
- 5:00 - OMST 1957 Mar # Omsk Time
+Zone Asia/Omsk 4:53:36 - LMT 1919 Nov 14
+ 5:00 - OMST 1930 Jun 21 # Omsk TIme
6:00 Russia OMS%sT 1991 Mar 31 2:00s
- 5:00 1:00 OMSST 1991 Sep 29 2:00s
- 5:00 - OMST 1992 Jan 19 2:00s
+ 5:00 Russia OMS%sT 1992 Jan 19 2:00s
6:00 Russia OMS%sT
# From Stanislaw A. Kuzikowski <S.A.Kuz@iae.nsk.su> (1994-06-29):
# But now it is some months since Novosibirsk is 3 hours ahead of Moscow!
# I do not know why they have decided to make this change;
# as far as I remember it was done exactly during winter->summer switching
# so we (Novosibirsk) simply did not switch.
-Zone Asia/Novosibirsk 5:31:40 - LMT 1924 May 2
- 6:00 - NOVT 1957 Mar # Novosibirsk Time
+Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
+ 6:00 - NOVT 1930 Jun 21 # Novosibirsk Time
7:00 Russia NOV%sT 1991 Mar 31 2:00s
- 6:00 1:00 NOVST 1991 Sep 29 2:00s
- 6:00 - NOVT 1992 Jan 19 2:00s
- 7:00 Russia NOV%sT 1994 Mar 27 2:00s
- 6:00 1:00 NOVST 1994 Sep 25 2:00s
+ 6:00 Russia NOV%sT 1992 Jan 19 2:00s
+ 7:00 Russia NOV%sT 1993 May 23 # says Shanks
6:00 Russia NOV%sT
-Zone Asia/Krasnoyarsk 6:11:20 - LMT 1924 May 2
- 6:00 - KRAT 1957 Mar # Krasnoyarsk Time
+Zone Asia/Krasnoyarsk 6:11:20 - LMT 1920 Jan 6
+ 6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time
7:00 Russia KRA%sT 1991 Mar 31 2:00s
- 6:00 1:00 KRAST 1991 Sep 29 2:00s
- 6:00 - KRAT 1992 Jan 19 2:00s
+ 6:00 Russia KRA%sT 1992 Jan 19 2:00s
7:00 Russia KRA%sT
Zone Asia/Irkutsk 6:57:20 - LMT 1880
- 6:57:20 - IMT 1924 May 2 # Irkutsk Mean Time
- 7:00 - IRKT 1957 Mar # Irkutsk Time
+ 6:57:20 - IMT 1920 Jan 25 # Irkutsk Mean Time
+ 7:00 - IRKT 1930 Jun 21 # Irkutsk Time
8:00 Russia IRK%sT 1991 Mar 31 2:00s
- 7:00 1:00 IRKST 1991 Sep 29 2:00s
- 7:00 - IRKT 1992 Jan 19 2:00s
+ 7:00 Russia IRK%sT 1992 Jan 19 2:00s
8:00 Russia IRK%sT
-Zone Asia/Yakutsk 8:38:40 - LMT 1924 May 2
- 8:00 - YAKT 1957 Mar # Yakutsk Time
+Zone Asia/Yakutsk 8:38:40 - LMT 1919 Dec 15
+ 8:00 - YAKT 1930 Jun 21 # Yakutsk Time
9:00 Russia YAK%sT 1991 Mar 31 2:00s
- 8:00 1:00 YAKST 1991 Sep 29 2:00s
- 8:00 - YAKT 1992 Jan 19 2:00s
+ 8:00 Russia YAK%sT 1992 Jan 19 2:00s
9:00 Russia YAK%sT
-Zone Asia/Vladivostok 8:47:44 - LMT 1880
- 8:47:44 - VMT 1924 May 2 # Vladivostok MT
- 9:00 - VLAT 1957 Mar # Vladivostok Time
+Zone Asia/Vladivostok 8:47:44 - LMT 1922 Nov 15
+ 9:00 - VLAT 1930 Jun 21 # Vladivostok Time
10:00 Russia VLA%sT 1991 Mar 31 2:00s
- 9:00 1:00 VLAST 1991 Sep 29 2:00s
- 9:00 - VLAT 1992 Jan 19 2:00s
+ 9:00 Russia VLA%sST 1992 Jan 19 2:00s
10:00 Russia VLA%sT
Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
- 10:00 - MAGT 1957 Mar # Magadan Time
+ 10:00 - MAGT 1930 Jun 21 # Magadan Time
11:00 Russia MAG%sT 1991 Mar 31 2:00s
- 10:00 1:00 MAGST 1991 Sep 29 2:00s
- 10:00 - MAGT 1992 Jan 19 2:00s
+ 10:00 Russia MAG%sT 1992 Jan 19 2:00s
11:00 Russia MAG%sT
# This name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
-Zone Asia/Kamchatka 10:34:36 - LMT 1924 May 2
- 11:00 - PETT 1957 Mar # P-K Time
+Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10
+ 11:00 - PETT 1930 Jun 21 # P-K Time
12:00 Russia PET%sT 1991 Mar 31 2:00s
- 11:00 1:00 PETST 1991 Sep 29 2:00s
- 11:00 - PETT 1992 Jan 19 2:00s
+ 11:00 Russia PET%sT 1992 Jan 19 2:00s
12:00 Russia PET%sT
Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2
- 12:00 - ANAT 1957 Mar # Anadyr Time
- 13:00 Russia ANA%sT 1991 Mar 31 2:00s
- 12:00 1:00 ANAST 1991 Sep 29 2:00s
- 12:00 - ANAT 1992 Jan 19 2:00s
- 13:00 Russia ANA%sT
+ 12:00 - ANAT 1930 Jun 21 # Anadyr Time
+ 13:00 Russia ANA%sT 1982 Apr 1 0:00s
+ 12:00 Russia ANA%sT 1991 Mar 31 2:00s
+ 11:00 Russia ANA%sT 1992 Jan 19 2:00s
+ 12:00 Russia ANA%sT
# Slovakia
Link Europe/Prague Europe/Bratislava
# Slovenia
-# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Europe/Ljubljana 0:58:04 - LMT 1884
- 1:00 - CET 1941 Apr 18 23:00
- 1:00 C-Eur CE%sT 1945 May 8 2:00s
- 1:00 1:00 CEST 1945 Sep 16 2:00s
- 1:00 - CET 1983
- 1:00 EU CE%sT
+# see Yugoslavia
# Spain
-# Gregorian calendar adopted 1582-10-15.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1; go with Shanks.
Rule Spain 1917 only - May 5 23:00s 1:00 S
Rule Spain 1939 only - Apr 15 23:00s 1:00 S
Rule Spain 1940 only - Mar 16 23:00s 1:00 S
# Whitman says no DST 1942-1945; go with Shanks.
-Rule Spain 1942 only - May 2 22:00s 2:00 DS
+Rule Spain 1942 only - May 2 22:00s 2:00 M # Midsummer
Rule Spain 1942 only - Sep 1 22:00s 1:00 S
-Rule Spain 1943 1946 - Apr Sat>=13 22:00s 2:00 DS
+Rule Spain 1943 1946 - Apr Sat>=13 22:00s 2:00 M
Rule Spain 1943 only - Oct 3 22:00s 1:00 S
Rule Spain 1944 only - Oct 10 22:00s 1:00 S
Rule Spain 1945 only - Sep 30 1:00 1:00 S
# Ignore this for now, as the Canaries are part of the EU.
# Sweden
-
-# From: msb@sq.com (Mark Brader) <URL:news:1996Jul6.012937.29190@sq.com>:
-#
-# In 1700, Denmark made the transition from Julian to Gregorian. Sweden
-# decided to *start* a transition in 1700 as well, but rather than have one of
-# those unsightly calendar gaps :-), they simply decreed that the next leap
-# year after 1696 would be in 1744 -- putting the whole country on a calendar
-# different from both Julian and Gregorian for a period of 40 years.
-#
-# However, in 1704 something went wrong and the plan was not carried through;
-# they did, after all, have a leap year that year. And one in 1708. In 1712
-# they gave it up and went back to Julian, putting 30 days in February that
-# year!...
-#
-# Then in 1753, Sweden made the transition to Gregorian in the usual manner,
-# getting there only 13 years behind the original schedule.
-#
-# (A previous posting of this story was challenged, and Swedish readers
-# produced the following references to support it: "Tiderakning och historia"
-# by Natanael Beckman (1924) and "Tid, en bok om tiderakning och
-# kalendervasen" by Lars-Olof Lode'n (no date was given).)
-
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Stockholm 1:12:12 - LMT 1878 May 31
1:12:12 - SMT 1900 Jan 1 1:00 # Stockholm MT
1:00 EU CE%sT
# Switzerland
-# From Howse (1988), p 82:
+# From Howse:
# By the end of the 18th century clocks and watches became commonplace
# and their performance improved enormously. Communities began to keep
# mean time in preference to apparent time -- Geneva from 1780 ....
# From Whitman (who writes ``Midnight?''):
Rule Swiss 1940 only - Nov 2 0:00 1:00 S
Rule Swiss 1940 only - Dec 31 0:00 0 -
-# From Shanks (1991):
+# From Shanks:
Rule Swiss 1941 1942 - May Sun>=1 2:00 1:00 S
Rule Swiss 1941 1942 - Oct Sun>=1 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Rule Turkey 1924 only - May 13 0:00 1:00 S
Rule Turkey 1924 1925 - Oct 1 0:00 0 -
Rule Turkey 1925 only - May 1 0:00 1:00 S
-# Shanks omits the first two transitions in 1940; go with Whitman.
Rule Turkey 1940 only - Jun 30 0:00 1:00 S
Rule Turkey 1940 only - Oct 5 0:00 0 -
Rule Turkey 1940 only - Dec 1 0:00 1:00 S
Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents.
# Ukraine
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Ukraine 1917 only - Jul 1 23:00 1:00 UST # Ukrainian Summer Time
-Rule Ukraine 1917 only - Dec 28 0:00 0 KMT # Kiev Mean Time
-Rule Ukraine 1918 only - May 31 22:00 2:00 UDST # Ukrainian Double Summer Time
-Rule Ukraine 1918 only - Sep 17 0:00 1:00 UST
-Rule Ukraine 1919 only - May 31 23:00 2:00 UDST
-Rule Ukraine 1919 only - Jul 1 2:00 1:00 UST
-Rule Ukraine 1919 only - Aug 16 0:00 0 KMT
-Rule Ukraine 1921 only - Feb 14 23:00 1:00 UST
-Rule Ukraine 1921 only - Mar 21 23:00 2:00 UDST
-Rule Ukraine 1921 only - Sep 1 0:00 1:00 UST
-Rule Ukraine 1921 only - Oct 1 0:00 0 KMT
-Rule Crimea 1917 only - Jul 1 23:00 1:00 CST # Crimean Summer Time
-Rule Crimea 1917 only - Dec 28 0:00 0 NMT # Nikolayev Mean Time
-Rule Crimea 1918 only - May 31 22:00 2:00 CDST # Crimean Double Summer Time
-Rule Crimea 1918 only - Sep 17 0:00 1:00 CST
-Rule Crimea 1919 only - May 31 23:00 2:00 CDST
-Rule Crimea 1919 only - Jul 1 2:00 1:00 CST
-Rule Crimea 1919 only - Aug 16 0:00 0 NMT
-Rule Crimea 1921 only - Feb 14 23:00 1:00 CST
-Rule Crimea 1921 only - Mar 21 23:00 2:00 CDST
-Rule Crimea 1921 only - Sep 1 0:00 1:00 CST
-Rule Crimea 1921 only - Oct 1 0:00 0 NMT
-Rule Crimea 1996 max - Mar lastSun 0:00u 1:00 -
-Rule Crimea 1996 max - Oct lastSun 0:00u 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+# Most of Ukraine since 1970 has been like Kiev.
Zone Europe/Kiev 2:02:04 - LMT 1880
- 2:02:04 Ukraine %s 1924 May 2
+ 2:02:04 - KMT 1924 May 2 # Kiev Mean Time
2:00 - EET 1930 Jun 21
- 3:00 Russia MSK/MSD 1990 Jul 17
- 2:00 E-Eur EE%sT 1996
+ 3:00 - MSK 1941 Sep 20
+ 1:00 C-Eur CE%sT 1943 Nov 6
+ 3:00 Russia MSK/MSD 1990
+ 3:00 - MSK 1990 Jul 1 2:00
+ 2:00 - EET 1992
+ 2:00 E-Eur EE%sT 1995
+ 2:00 EU EE%sT
+# Ruthenia used CET 1990/1991.
+Zone Europe/Uzhgorod 1:29:12 - LMT 1890 Oct
+ 1:00 - CET 1940
+ 1:00 C-Eur CE%sT 1944 Oct
+ 1:00 1:00 CEST 1944 Oct 26
+ 1:00 - CET 1945 Jun 29
+ 3:00 Russia MSK/MSD 1990
+ 3:00 - MSK 1990 Jul 1 2:00
+ 1:00 - CET 1991 Mar 31 3:00
+ 2:00 - EET 1992
+ 2:00 E-Eur EE%sT 1995
2:00 EU EE%sT
+# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991.
+# Zaporozh'ye has an apostrophe, but Posix file names can't have apostrophes.
+Zone Europe/Zaporozhye 2:20:40 - LMT 1880
+ 2:20 - CUT 1924 May 2 # Central Ukraine T
+ 2:00 - EET 1930 Jun 21
+ 3:00 - MSK 1941 Aug 25
+ 1:00 C-Eur CE%sT 1943 Oct 25
+ 3:00 Russia MSK/MSD 1991 Mar 31 2:00
+ 2:00 E-Eur EE%sT 1995
+ 2:00 EU EE%sT
+# Central Crimea used Moscow time 1994/1997.
Zone Europe/Simferopol 2:16:24 - LMT 1880
- 2:08:00 Crimea %s 1924 May 2
+ 2:16 - SMT 1924 May 2 # Simferopol Mean T
2:00 - EET 1930 Jun 21
- 3:00 Russia MSK/MSD 1991 Mar 31 2:00s
- 2:00 1:00 EEST 1991 Sep 29 2:00s
-# From Paul Eggert <eggert@twinsun.com> (1996-10-21):
-# The _Economist_ (1994-05-28, p 45) reports that most of Crimea switched
+ 3:00 - MSK 1941 Nov
+ 1:00 C-Eur CE%sT 1944 Apr 13
+ 3:00 Russia MSK/MSD 1990
+ 3:00 - MSK 1990 Jul 1 2:00
+ 2:00 - EET 1992
+# From Paul Eggert <eggert@twinsun.com> (1999-11-12):
+# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
# from Kiev to Moscow time sometime after the January 1994 elections.
-# For now, guess it changed Feb 1.
- 2:00 C-Eur EE%sT 1994 Feb
-# From IATA SSIM (1994/1996), which also says that Kerch is still like Kiev.
- 3:00 E-Eur MSK/MSD 1996
- 3:00 Crimea MSK/MSD
+# Shanks says ``date of change uncertain'', but implies that it happened
+# sometime between the 1994 DST switches. For now, guess it changed in May.
+ 2:00 E-Eur EE%sT 1994 May
+# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
+ 3:00 E-Eur MSK/MSD 1996 Mar 31 3:00s
+ 3:00 1:00 MSD 1996 Oct 27 3:00s
+# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
+# Assume it happened in March by not changing the clocks.
+ 3:00 Russia MSK/MSD 1997
+ 3:00 - MSK 1997 Mar lastSun 1:00u
+ 2:00 EU EE%sT
# Yugoslavia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
1:00 - CET 1941 Apr 18 23:00
1:00 C-Eur CE%sT 1945 May 8 2:00s
1:00 1:00 CEST 1945 Sep 16 2:00s
- 1:00 - CET 1983
+# Metod Kozelj <metod.kozelj@rzs-hm.si> reports that the legal date of
+# transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
+# Shanks doesn't give as much detail, so go with Kozelj.
+ 1:00 - CET 1982 Nov 27
1:00 EU CE%sT
+Link Europe/Belgrade Europe/Ljubljana # Slovenia
+Link Europe/Belgrade Europe/Sarajevo # Bosnia and Herzegovina
+Link Europe/Belgrade Europe/Skopje # Macedonia
+Link Europe/Belgrade Europe/Zagreb # Croatia
###############################################################################
# ...
# Monaco: has same DST as France.
# ...
-
-# ...
-# Date: Fri, 3 Sep 93 13:43:41 BST
-# From: Peter Ilieve <peter@memex.co.uk>
-# ...
-# Turning to Europe, I now have a copy of the `Sixth Council Directive 92/20/EEC
-# of 26 March 1992 on summertime arrangements'. This only covers 1993 and
-# 1994, a seventh one is in the works but I doubt that the algorithm will
-# change. This says summertime starts at 01:00 GMT on the last Sunday in March
-# and ends at 01:00 GMT on the last Sunday in September, except for the UK
-# and Eire where it ends at 01:00 GMT on the fourth Sunday in October.
-# It says the arrangements for 1995 onwards will be decided by 1 January 1994,
-# but as the sixth directive was supposed to appear by 1 Jan 92 and didn't
-# arrive til March I wouldn't hold your breath.
-#
-# The first summertime directive was adopted in 1980, although the UK didn't
-# seem to use it until 1981. I suspect it would be safe to move your start
-# dates for the -Eur rules back to 1981.
-# $OpenBSD: factory,v 1.2 1997/01/14 04:36:53 millert Exp $
-# @(#)factory 7.1
+# @(#)factory 7.3
# For companies who don't want to put time zone specification in
# their installation procedures. When users run date, they'll get the message.
# Also useful for the "comp.sources" version.
# Zone NAME GMTOFF RULES FORMAT
-Zone Factory 0 - "Local time zone must be set--see zic manual page"
+Zone Factory 0 - "Local time zone must be set--use tzsetup"
-# $OpenBSD: leapseconds,v 1.2 1997/01/14 04:36:54 millert Exp $
-# @(#)leapseconds 7.8
+# @(#)leapseconds 7.13
+
+# $FreeBSD: src/share/zoneinfo/leapseconds,v 1.6 2001/04/06 16:46:52 wollman Exp $
# Allowance for leapseconds added to each timezone file.
# The International Earth Rotation Service periodically uses leap seconds
-# to keep UTC to within 0.9 s of TAI (atomic time); see
+# to keep UTC to within 0.9 s of UT1
+# (which measures the true angular orientation of the earth in space); see
# Terry J Quinn, The BIPM and the accurate measure of time,
# Proc IEEE 79, 7 (July 1991), 894-905.
# There were no leap seconds before 1972, because the official mechanism
# Leap YEAR MON DAY 23:59:59 - R/S
# If the leapsecond is Rolling (R) the given time is local time
-# If the leapsecond is Stationary (S) the given time is GMT
+# If the leapsecond is Stationary (S) the given time is UTC
# Leap YEAR MONTH DAY HH:MM:SS CORR R/S
Leap 1972 Jun 30 23:59:60 + S
Leap 1993 Jun 30 23:59:60 + S
Leap 1994 Jun 30 23:59:60 + S
Leap 1995 Dec 31 23:59:60 + S
+Leap 1997 Jun 30 23:59:60 + S
+Leap 1998 Dec 31 23:59:60 + S
+# INTERNATIONAL EARTH ROTATION SERVICE (IERS)
+# SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE
+#
+# SERVICE DE LA ROTATION TERRESTRE
+# OBSERVATOIRE DE PARIS
+# 61, Av. de l'Observatoire 75014 PARIS (France)
+# Tel. : 33 (0) 1 40 51 22 26
+# FAX : 33 (0) 1 40 51 22 91
+# Internet : iers@obspm.fr
+#
+# Paris, 11 January 2001
+#
+# Bulletin C 21
+#
+# To authorities responsible for the measurement and distribution of time
+#
+# INFORMATION ON UTC - TAI
+#
+# NO positive leap second will be introduced at the end of June 2001.
-# $OpenBSD: northamerica,v 1.5 1997/01/14 04:36:54 millert Exp $
-# @(#)northamerica 7.30
+# @(#)northamerica 7.58
# also includes Central America and the Caribbean
+# $FreeBSD: src/share/zoneinfo/northamerica,v 1.18 2001/04/06 16:46:52 wollman Exp $
+
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1994-08-17):
+# From Paul Eggert <eggert@twinsun.com> (1999-03-22):
# A reliable and entertaining source about time zones is
-# Derek Howse, Greenwich time and the discovery of the longitude,
-# Oxford University Press (1980).
+# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
###############################################################################
# United States
+# From Paul Eggert (1999-03-31):
+# Howse writes (pp 121-125) that time zones were invented by
+# Professor Charles Ferdinand Dowd (1825-1904),
+# Principal of Temple Grove Ladies' Seminary (Saratoga Springs, NY).
+# His pamphlet ``A System of National Time for Railroads'' (1870)
+# was the result of his proposals at the Convention of Railroad Trunk Lines
+# in New York City (1869-10). His 1870 proposal was based on Washington, DC,
+# but in 1872-05 he moved the proposed origin to Greenwich.
+# His proposal was adopted by the railroads on 1883-11-18 at 12:00,
+# and the most of the country soon followed suit.
+
# From Paul Eggert <eggert@twinsun.com> (1995-12-19):
# A good source for time zone historical data in the US is
# Thomas G. Shanks, The American Atlas (5th edition),
# Make sure you have the errata sheet; the book is somewhat useless without it.
# It is the source for the US and Puerto Rico entries below.
-# From Paul Eggert (1996-06-12):
+# From Paul Eggert (2001-03-06):
# Daylight Saving Time was first suggested as a joke by Benjamin Franklin
-# in his whimsical essay ``Turkey vs Eagle, McCauley is my Beagle'' (1784).
+# in his whimsical essay ``An Economical Project for Diminishing the Cost
+# of Light'' published in the Journal de Paris (1784-04-26).
# Not everyone is happy with the results:
#
# I don't really care how time is reckoned so long as there is some
# them healthy, wealthy and wise in spite of themselves.
#
# -- Robertson Davies, The Diary of Samuel Marchbanks (1947), XIX, Sunday
+#
+# For more about the first ten years of DST in the United States, see
+# Robert Garland's <a href="http://www.clpgh.org/exhibit/dst.html">
+# Ten years of daylight saving from the Pittsburgh standpoint
+# (Carnegie Library of Pittsburgh, 1927)</a>.
+#
+# Shanks says that DST was called "War Time" in the US in 1918 and 1919.
+# However, DST was imposed by the Standard Time Act of 1918, which
+# was the first nationwide legal time standard, and apparently
+# time was just called "Standard Time" or "Daylight Saving Time".
# From Arthur David Olson:
# US Daylight Saving Time ended on the last Sunday of *October* in 1974.
# Before the Uniform Time Act of 1966 took effect in 1967, observance of
# Daylight Saving Time in the US was by local option, except during wartime.
+# From Arthur David Olson (2000-09-25):
+# Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
+# In the introduction, Oboler spoke of "Eastern Peace Time."
+# An AltaVista search turned up
+# <a href="http://rowayton.org/rhs/hstaug45.html">:
+# "When the time is announced over the radio now, it is 'Eastern Peace
+# Time' instead of the old familiar 'Eastern War Time.' Peace is wonderful."
+# </a> (August 1945) by way of confirmation.
+
+# From Joseph Gallant <notquite@hotmail.com>, citing
+# George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
+# At 7 P.M. (Eastern War Time) [on 1945-08-14], the networks were set
+# to switch to London for Atlee's address, but the American people
+# never got to hear his speech live. According to one press account,
+# CBS' Bob Trout was first to announce the word of Japan's surrender,
+# but a few seconds later, NBC, ABC and Mutual also flashed the word
+# of surrender, all of whom interrupting the bells of Big Ben in
+# London which were to precede Mr. Atlee's speech.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule US 1918 1919 - Mar lastSun 2:00 1:00 W # War
+Rule US 1918 1919 - Mar lastSun 2:00 1:00 D
Rule US 1918 1919 - Oct lastSun 2:00 0 S
Rule US 1942 only - Feb 9 2:00 1:00 W # War
+Rule US 1945 only - Aug 14 23:00u 1:00 P # Peace
Rule US 1945 only - Sep 30 2:00 0 S
Rule US 1967 max - Oct lastSun 2:00 0 S
Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
Rule US 1975 only - Feb 23 2:00 1:00 D
Rule US 1976 1986 - Apr lastSun 2:00 1:00 D
Rule US 1987 max - Apr Sun>=1 2:00 1:00 D
+# <a href="http://thomas.loc.gov/cgi-bin/bdquery/z?d106:h.r.00177:">
+# H.R.177
+# </a> (introduced 1999-01-06) would change April to March in the above rule.
# From Bob Devine (1988-01-28):
# ...Alaska (and Hawaii) had the timezone names changed in 1967.
# From Paul Eggert (1995-12-19):
# Shanks uses 1983-10-30, not 1983-11-30, for the 1983 transitions.
# Go with Shanks.
+#
+# From Paul Eggert (2000-01-08), following a heads-up from Rives McDow:
+# Public law 106-564 (2000-12-23) introduced the abbreviation
+# "Chamorro Standard Time" for time in Guam and the Northern Marianas.
+# See the file "australasia".
+
+# From Ryan Alessi of the Thousand Oaks Star (2001-02-15) via Rives McDow:
+# Brad Sherman, D-Sherman Oaks, introduced a bill in Congress on
+# Wednesday that could have California operating on Denver time as
+# early as this summer.... The options include keeping
+# daylight-saving time all year long, or setting clocks back two hours
+# -- instead of just one -- during the existing daylight-saving time.
+
# US Eastern time, represented by New York
+
+# Connecticut, Delaware, District of Columbia, most of Florida,
+# Georgia, far southeastern Indiana, eastern Kentucky, Maine,
+# Maryland, Massachusetts, New Hampshire, New Jersey, New York, North
+# Carolina, Ohio, Pennsylvania, Rhode Island, South Carolina, eastern
+# Tennessee, Vermont, Virginia, West Virginia
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule NYC 1920 only - Mar lastSun 2:00 1:00 D
Rule NYC 1920 only - Oct lastSun 2:00 0 S
-5:00 US E%sT
# US Central time, represented by Chicago
+
+# Alabama, Arkansas, Florida panhandle, Illinois, western Indiana
+# corners, Iowa, most of Kansas, western Kentucky, Louisiana,
+# Minnesota, Mississippi, Missouri, eastern Nebraska, eastern North
+# Dakota, Oklahoma, eastern South Dakota, western Tennessee, most of
+# Texas, Wisconsin
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule Chicago 1920 only - Jun 13 2:00 1:00 D
Rule Chicago 1920 1921 - Oct lastSun 2:00 0 S
-6:00 US C%sT
# US Mountain time, represented by Denver
+#
+# Colorado, southern Idaho, far western Kansas, Montana, western
+# Nebraska, New Mexico, southwestern North Dakota, far eastern Oregon,
+# western South Dakota, far western Texas (El Paso County, Hudspeth County,
+# and Pine Springs and Nickel Creek in Culberson County), Utah, Wyoming
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule Denver 1920 1921 - Mar lastSun 2:00 1:00 D
Rule Denver 1920 only - Oct lastSun 2:00 0 S
-7:00 US M%sT
# US Pacific time, represented by Los Angeles
+#
+# California, northern Idaho, Nevada, most of Oregon, and Washington
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule CA 1948 only - Mar 14 2:00 1:00 D
Rule CA 1949 only - Jan 1 2:00 0 S
# Alaska
# AK%sT is the modern abbreviation for -9:00 per USNO.
#
-# From Paul Eggert (1995-12-19):
+# From Paul Eggert (2001-04-01):
# Howse writes that Alaska switched from the Julian to the Gregorian calendar,
# and from east-of-GMT to west-of-GMT days, when the US bought it from Russia.
-# This was on 1867-10-18. We omit this transition, since we can't represent
-# changes from Julian to Gregorian.
+# This was on 1867-10-18, a Friday; the previous day was 1867-10-06 Julian,
+# also a Friday. Include only the time zone part of this transition,
+# ignoring the switch from Julian to Gregorian, since we can't represent
+# the Julian calendar.
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone America/Juneau -8:57:41 - LMT 1900 Aug 20 12:00
+Zone America/Juneau 15:02:19 - LMT 1867 Oct 18
+ -8:57:41 - LMT 1900 Aug 20 12:00
-8:00 - PST 1942
-8:00 US P%sT 1946
-8:00 - PST 1969
-8:00 US P%sT 1983 Oct 30 2:00
-9:00 US AK%sT
-Zone America/Yakutat -9:18:55 - LMT 1900 Aug 20 12:00
+Zone America/Yakutat 14:41:05 - LMT 1867 Oct 18
+ -9:18:55 - LMT 1900 Aug 20 12:00
-9:00 - YST 1942
-9:00 US Y%sT 1946
-9:00 - YST 1969
-9:00 US Y%sT 1983 Oct 30 2:00
-9:00 US AK%sT
-Zone America/Anchorage -9:59:36 - LMT 1900 Aug 20 12:00
+Zone America/Anchorage 14:00:24 - LMT 1867 Oct 18
+ -9:59:36 - LMT 1900 Aug 20 12:00
-10:00 - CAT 1942
-10:00 US CAT/CAWT 1946
-10:00 - CAT 1967 Apr
-10:00 - AHST 1969
-10:00 US AH%sT 1983 Oct 30 2:00
-9:00 US AK%sT
-Zone America/Nome -11:01:38 - LMT 1900 Aug 20 12:00
+Zone America/Nome 12:58:21 - LMT 1867 Oct 18
+ -11:01:38 - LMT 1900 Aug 20 12:00
-11:00 - NST 1942
-11:00 US N%sT 1946
-11:00 - NST 1967 Apr
-11:00 - BST 1969
-11:00 US B%sT 1983 Oct 30 2:00
-9:00 US AK%sT
-Zone America/Adak -11:46:38 - LMT 1900 Aug 20 12:00
+Zone America/Adak 12:13:21 - LMT 1867 Oct 18
+ -11:46:38 - LMT 1900 Aug 20 12:00
-11:00 - NST 1942
-11:00 US N%sT 1946
-11:00 - NST 1967 Apr
-10:30 US H%sT 1947 Jun 8 2:00
-10:00 - HST
-Zone Pacific/Midway -11:49:28 - LMT 1901
- -11:00 - NST 1967 Apr # N=Nome
- -11:00 - BST 1983 Nov 30 # B=Bering
- -11:00 - SST # S=Samoa
-
# Now we turn to US areas that have diverged from the consensus since 1970.
# Arizona mostly uses MST.
# Indiana
#
+# For a map of Indiana's time zone regions, see:
+# <a href="http://www.mccsc.edu/time.html">
+# What time is it in Indiana?
+# </a> (1999-04-06)
+#
# From Paul Eggert (1995-12-19):
# Indiana generally observes either EST all year, or CST/CDT,
# but areas near Cincinnati and Louisville use those cities' timekeeping
# So we reluctantly put them all in a subdirectory `America/Indiana'.
#
# Most of EST-only Indiana last observed DST in 1970.
+
+# From Paul Eggert (2001-03-06), following a tip by Markus Kuhn:
+# Pam Belluck reported in the New York Times (2001-01-31) that the
+# Indiana Legislature is considering a bill to adopt DST statewide.
+# Her article mentioned Vevay, whose post office observes a different
+# time zone than Danner's Hardware across the street.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule Indianapolis 1941 only - Jun 22 2:00 1:00 D
Rule Indianapolis 1941 1954 - Sep lastSun 2:00 0 S
-5:00 - EST
# Part of Kentucky left its clocks alone in 1974.
+# This also includes a part of Indiana immediately adjacent to Louisville.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule Louisville 1921 only - May 1 2:00 1:00 D
Rule Louisville 1921 only - Sep 1 2:00 0 S
-5:00 US E%sT 1974 Jan 6 2:00
-6:00 1:00 CDT 1974 Oct 27 2:00
-5:00 US E%sT
+Link America/Louisville America/Kentucky/Louisville
+#
+# Wayne, Clinton, and Russell Counties, Kentucky
+#
+# From
+# <a href="http://www.lake-cumberland.com/life/archive/news990129time.shtml">
+# Lake Cumberland LIFE
+# </a> (1999-01-29) via WKYM-101.7:
+# Clinton County has joined Wayne County in asking the DoT to change from
+# the Central to the Eastern time zone.... The Wayne County government made
+# the same request in December. And while Russell County officials have not
+# taken action, the majority of respondents to a poll conducted there in
+# August indicated they would like to change to "fast time" also.
+# The three Lake Cumberland counties are the farthest east of any U.S.
+# location in the Central time zone.
+#
+# From Rich Wales (2000-08-29):
+# After prolonged debate, and despite continuing deep differences of opinion,
+# Wayne County (central Kentucky) is switching from Central (-0600) to Eastern
+# (-0500) time. They won't "fall back" this year. See Sara Shipley,
+# The difference an hour makes, Nando Times (2000-08-29 15:33 -0400).
+Zone America/Kentucky/Monticello -5:39:24 - LMT 1883 Nov 18 12:00
+ -6:00 US C%sT 1946
+ -6:00 - CST 1968
+ -6:00 US C%sT 2000 Oct 29 2:00
+ -5:00 US E%sT
+
+
+# From Rives McDow (2000-08-30):
+# Here ... are all the changes in the US since 1985.
+# Kearny County, KS (put all of county on central;
+# previously split between MST and CST) ... 1990-10
+# Starke County, IN (from CST to EST) ... 1991-10
+# Oliver County, ND (from MST to CST) ... 1992-10
+# West Wendover, NV (from PST TO MST) ... 1999-10
+# Wayne County, KY (from CST to EST) ... 2000-10
+# There is another change in the offing; Mercer County, ND is looking
+# to change from MT to CT. It is possible that two other ND counties
+# (Sioux and Morton) will look to change also. If made, the earliest
+# a change would be effective is October 2001.
+#
+# From Paul Eggert (2000-10-02):
+# FIXME: I haven't yet had time to incorporate all the above changes.
# Michigan
#
# From Bob Devine (1988-01-28):
# Michigan didn't observe DST from 1968 to 1973.
#
-# From Paul Eggert (1995-12-19):
-# Shanks writes that Michigan started using standard time on 1885 Sep 18,
-# but Howse (p 126) writes that Detroit kept
+# From Paul Eggert (1999-03-31):
+# Shanks writes that Michigan started using standard time on 1885-09-18,
+# but Howse writes (pp 124-125, referring to Popular Astronomy, 1901-01)
+# that Detroit kept
#
# local time until 1900 when the City Council decreed that clocks should
# be put back twenty-eight minutes to Central Standard Time. Half the
#
# This story is too entertaining to be false, so go with Howse over Shanks.
#
+# From Paul Eggert (2001-03-06):
+# Garland (1927) writes ``Cleveland and Detroit advanced their clocks
+# one hour in 1914.'' This change is not in Shanks. We have no more
+# info, so omit this for now.
+#
# Most of Michigan observed DST from 1973 on, but was a bit late in 1975.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule Detroit 1948 only - Apr lastSun 2:00 1:00 D
-6:00 US C%sT
# Navassa
-# uninhabited
-
+# claimed by US under the provisions of the 1856 Guano Islands Act
+# also claimed by Haiti
+# occupied 1857/1900 by the Navassa Phosphate Co
+# US lighthouse 1917/1997-01
+# currently uninhabited
+# see Mark Fineman, ``An Isle Rich in Guano and Discord'',
+# _Los Angeles Times_ (1998-11-10), A1, A10; it cites
+# Jimmy Skaggs, _The Great Guano Rush_ (1994).
# Old names, for S5 users
################################################################################
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-10-29):
# A good source for time zone historical data outside the US is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# I found in the UCLA library.
#
# See the `europe' file for Greenland.
-#
-# See the `africa' file for time zone naming and abbreviation conventions.
# Canada
# From Paul Eggert <eggert@twinsun.com> (1994-11-22):
# Alas, this sort of thing must be handled by localization software.
-# The data for Canada are all from Shanks (1991).
+# Unless otherwise specified, the data for Canada are all from Shanks.
+# From Paul Eggert (2000-10-02):
+# H. David Matthews and Mary Vincent's map
+# <a href="http://www.canadiangeographic.ca/SO98/geomap.htm">
+# "It's about TIME", _Canadian Geographic_ (September-October 1998)
+# </a> contains detailed boundaries for regions observing nonstandard
+# time and daylight saving time arrangements in Canada circa 1998.
+#
+# INMS, the Institute for National Measurement Standards in Ottawa, has
+# <a href="http://www.nrc.ca/inms/time/tze.html">
+# information about standard and daylight saving time zones in Canada.
+# </a> (updated periodically).
+# Its unofficial information is often taken from Matthews and Vincent.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Canada 1918 only - Apr 14 2:00 1:00 D
Rule Canada 1918 only - Oct 31 2:00 0 S
-Rule Canada 1942 only - Feb 9 2:00 1:00 D
+Rule Canada 1942 only - Feb 9 2:00 1:00 W
Rule Canada 1945 only - Sep 30 2:00 0 S
Rule Canada 1974 1986 - Apr lastSun 2:00 1:00 D
Rule Canada 1974 max - Oct lastSun 2:00 0 S
Rule Canada 1987 max - Apr Sun>=1 2:00 1:00 D
-# Newfoundland (except Labrador)
+# Newfoundland (and far southeast Labrador)
+
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) write that Labrador should use NST/NDT,
+# but the only part of Labrador that follows the rules is the
+# southeast corner, including Port Hope Simpson and Mary's Harbour,
+# but excluding, say, Black Tickle.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule StJohns 1917 1918 - Apr Sun>=8 2:00 1:00 D
Rule StJohns 1936 1941 - May Sun>=8 0:00 1:00 D
Rule StJohns 1936 1941 - Oct Sun>=1 0:00 0 S
# Shanks gives 1942 May 11 - 1945 Sep 30; go with Whitman.
-Rule StJohns 1942 only - Mar 1 0:00 1:00 D
+Rule StJohns 1942 only - Mar 1 0:00 1:00 W
Rule StJohns 1942 only - Dec 31 0:00 0 S
-Rule StJohns 1943 only - May 30 0:00 1:00 D
+Rule StJohns 1943 only - May 30 0:00 1:00 W
Rule StJohns 1943 only - Sep 5 0:00 0 S
-Rule StJohns 1944 only - Jul 10 0:00 1:00 D
+Rule StJohns 1944 only - Jul 10 0:00 1:00 W
Rule StJohns 1944 only - Sep 2 0:00 0 S
-Rule StJohns 1945 only - Jan 1 0:00 1:00 D
+Rule StJohns 1945 only - Jan 1 0:00 1:00 W
Rule StJohns 1945 only - Oct 7 2:00 0 S
# For 1946-9 Whitman gives May 5,4,9,1 - Oct 1,5,3,2, and for 1950 he gives
# Apr 30 - Sep 24; go with Shanks.
Rule StJohns 1946 1950 - Oct Sun>=2 2:00 0 S
Rule StJohns 1951 1986 - Apr lastSun 2:00 1:00 D
Rule StJohns 1951 1959 - Sep lastSun 2:00 0 S
-Rule StJohns 1960 max - Oct lastSun 2:00 0 S
-Rule StJohns 1987 only - Apr Sun>=1 2:00 1:00 D
-Rule StJohns 1988 only - Apr Sun>=1 2:00 2:00 DD
-Rule StJohns 1989 max - Apr Sun>=1 2:00 1:00 D
+Rule StJohns 1960 1986 - Oct lastSun 2:00 0 S
+# From Paul Eggert (2000-10-02):
+# INMS (2000-09-12) says that, since 1988 at least, Newfoundland switches
+# at 00:01 local time. For now, assume it started in 1987.
+Rule StJohns 1987 only - Apr Sun>=1 0:01 1:00 D
+Rule StJohns 1987 max - Oct lastSun 0:01 0 S
+Rule StJohns 1988 only - Apr Sun>=1 0:01 2:00 DD
+Rule StJohns 1989 max - Apr Sun>=1 0:01 1:00 D
# St John's has an apostrophe, but Posix file names can't have apostrophes.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/St_Johns -3:30:52 - LMT 1884
-3:30 StJohns N%sT
-# east Labrador
+# most of east Labrador
# The name `Happy Valley-Goose Bay' is too long; use `Goose Bay'.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Shanks also writes that Liverpool, NS was the only town in Canada to observe
# DST in 1971 but not 1970; for now we'll assume this is a typo.
+# From Paul Eggert (2000-10-02):
+# INMS (2000-09-12) says that, since 1988 at least, New Brunswick switches
+# at 00:01 local time. FIXME: verify and create a new Zone for this.
+
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Halifax 1916 only - Apr 1 0:00 1:00 D
Rule Halifax 1916 only - Oct 1 0:00 0 S
Rule Halifax 1937 1941 - Sep Mon>=24 0:00 0 S
Rule Halifax 1939 only - May 28 0:00 1:00 D
Rule Halifax 1940 1941 - May Sun>=1 0:00 1:00 D
-Rule Halifax 1942 only - Feb 9 2:00 1:00 D
+Rule Halifax 1942 only - Feb 9 2:00 1:00 W
Rule Halifax 1945 1959 - Sep lastSun 2:00 0 S
Rule Halifax 1946 1959 - Apr lastSun 2:00 1:00 D
Rule Halifax 1962 1986 - Apr lastSun 2:00 1:00 D
# Nipigon (EST) and Rainy River (CST) are the largest that we know of.
# Far west Ontario is like Winnipeg; far east Quebec is like Halifax.
+# From Paul Eggert (1997-10-17):
+# msb@sq.com writes that an article in the 1997-10-14 Toronto Star
+# says that Atikokan, Ontario currently does not observe DST,
+# but will vote on 11-10 whether to use EST/EDT.
+# He also writes that the
+# <a href="http://www.gov.on.ca/MBS/english/publications/statregs/conttext.html">
+# Ontario Time Act (1990, Chapter T.9)
+# </a>
+# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
+# Officially Atikokan is therefore on CST/CDT, and most likely this report
+# concerns a non-official time observed as a matter of local practice.
+# For what it's worth, Shanks says that Atikokan has agreed with
+# Rainy River ever since standard time was introduced.
+
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and
+# New Osnaburgh observe CST all year, that Big Trout Lake observes
+# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in
+# violation of the official Ontario rules.
+# They also write that Quebec east of the -63 meridian is supposed to
+# observe AST, but residents as far east as Natashquan use EST/EDT,
+# and residents east of Natashquan use AST.
+# We probably need Zones for far east Quebec and for Atikokan,
+# but we don't know when their practices started.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Mont 1917 only - Mar 25 2:00 1:00 D
Rule Mont 1917 only - Apr 24 0:00 0 S
Rule Winn 1918 only - Oct 31 2:00 0 S
Rule Winn 1937 only - May 16 2:00 1:00 D
Rule Winn 1937 only - Sep 26 2:00 0 S
-Rule Winn 1942 only - Feb 9 2:00 1:00 D
+Rule Winn 1942 only - Feb 9 2:00 1:00 W
Rule Winn 1945 only - Sep lastSun 2:00 0 S
Rule Winn 1946 only - May 12 2:00 1:00 D
Rule Winn 1946 only - Oct 13 2:00 0 S
Rule Winn 1963 only - Apr lastSun 2:00 1:00 D
Rule Winn 1963 only - Sep 22 2:00 0 S
Rule Winn 1966 1986 - Apr lastSun 2:00 1:00 D
-Rule Winn 1966 max - Oct lastSun 2:00 0 S
+Rule Winn 1966 1986 - Oct lastSun 2:00 0 S
Rule Winn 1987 max - Apr Sun>=1 2:00 1:00 D
+# From Paul Eggert (2000-10-02):
+# INMS (2000-09-12) says that, since 1988 at least, Manitoba switches from
+# DST at 03:00 local time. For now, assume it started in 1987.
+Rule Winn 1987 max - Oct lastSun 2:00s 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Winnipeg -6:28:36 - LMT 1887 Jul 16
-6:00 Winn C%sT
# Saskatchewan
-# From Paul Eggert (1996-06-12):
+# From Paul Eggert (2000-10-02):
# Shanks writes that since 1970 most of this region has been like Regina.
# Some western towns (e.g. Swift Current) switched from MST/MDT to CST in 1972.
# Other western towns (e.g. Lloydminster) are like Edmonton.
+# Matthews and Vincent (1998) write that Denare Beach and Creighton
+# are like Winnipeg, in violation of Saskatchewan law.
# From W. Jones <jones@skdad.usask.ca> (1992-11-06):
# The. . .below is based on information I got from our law library, the
Rule Regina 1937 only - Oct Sun>=8 0:00 0 S
Rule Regina 1938 only - Oct Sun>=1 0:00 0 S
Rule Regina 1939 1941 - Oct Sun>=8 0:00 0 S
-Rule Regina 1942 only - Feb 9 2:00 1:00 D
+Rule Regina 1942 only - Feb 9 2:00 1:00 W
Rule Regina 1945 only - Sep lastSun 2:00 0 S
Rule Regina 1946 only - Apr Sun>=8 2:00 1:00 D
Rule Regina 1946 only - Oct Sun>=8 2:00 0 S
Rule Edm 1920 1923 - Apr lastSun 2:00 1:00 D
Rule Edm 1920 only - Oct lastSun 2:00 0 S
Rule Edm 1921 1923 - Sep lastSun 2:00 0 S
-Rule Edm 1942 only - Feb 9 2:00 1:00 D
+Rule Edm 1942 only - Feb 9 2:00 1:00 W
Rule Edm 1945 only - Sep lastSun 2:00 0 S
Rule Edm 1947 only - Apr lastSun 2:00 1:00 D
Rule Edm 1947 only - Sep lastSun 2:00 0 S
# British Columbia
-# From Paul Eggert (1996-06-12):
+# From Paul Eggert (2000-10-02):
# Shanks writes that since 1970 most of this region has been like Vancouver.
-# Dawswon Creek uses MST. Much of east BC is like Edmonton.
+# Dawson Creek uses MST. Much of east BC is like Edmonton.
+# Matthews and Vincent (1998) write that Creston is like Dawson Creek.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Vanc 1918 only - Apr 14 2:00 1:00 D
Rule Vanc 1918 only - Oct 31 2:00 0 S
-Rule Vanc 1942 only - Feb 9 2:00 1:00 D
+Rule Vanc 1942 only - Feb 9 2:00 1:00 W
Rule Vanc 1945 only - Sep 30 2:00 0 S
Rule Vanc 1946 1986 - Apr lastSun 2:00 1:00 D
Rule Vanc 1946 only - Oct 13 2:00 0 S
-7:00 - MST
-# Northwest Territories, Yukon
+# Northwest Territories, Nunavut, Yukon
-# From Paul Eggert (1996-10-07):
+# From Paul Eggert (1999-10-29):
# Dawson switched to PST in 1973. Inuvik switched to MST in 1979.
-# Shanks's table for Watson Lake is corrupted, so we have no data there.
# Mathew Englander <mathew@io.org> (1996-10-07) gives the following refs:
# * 1967. Paragraph 28(34)(g) of the Interpretation Act, S.C. 1967-68,
# c. 7 defines Yukon standard time as UTC-9. This is still valid;
# * O.I.C. 1987/056 changed DST to Apr firstSun 2:00 to Oct lastSun 2:00.
# Shanks says Yukon's 1973-10-28 switch was at 2:00; go with Englander.
+# From Rives McDow (1999-09-04):
+# Nunavut ... moved ... to incorporate the whole territory into one time zone.
+# <a href="http://www.nunatsiaq.com/nunavut/nvt90903_13.html">
+# Nunavut moves to single time zone Oct. 31
+# </a>
+#
+# From Antoine Leca (1999-09-06):
+# We then need to create a new timezone for the Kitikmeot region of Nunavut
+# to differentiate it from the Yellowknife region.
+
+# From Paul Eggert (1999-09-20):
+# <a href="http://www.nunavut.com/basicfacts/english/basicfacts_1territory.html">
+# Basic Facts: The New Territory
+# </a> (1999) reports that Pangnirtung operates on Eastern time,
+# and that Coral Harbour does not observe DST. We don't know when
+# Pangnirtung switched to Eastern time; we'll guess 1995.
+# We'll ignore the claim about Coral Harbour for now,
+# since we have no further info.
+
+# From Rives McDow (1999-11-08):
+# On October 31, when the rest of Nunavut went to Central time,
+# Pangnirtung wobbled. Here is the result of their wobble:
+#
+# The following businesses and organizations in Pangnirtung use Central Time:
+#
+# First Air, Power Corp, Nunavut Construction, Health Center, RCMP,
+# Eastern Arctic National Parks, A & D Specialist
+#
+# The following businesses and organizations in Pangnirtung use Eastern Time:
+#
+# Hamlet office, All other businesses, Both schools, Airport operator
+#
+# This has made for an interesting situation there, which warranted the news.
+# No one there that I spoke with seems concerned, or has plans to
+# change the local methods of keeping time, as it evidently does not
+# really interfere with any activities or make things difficult locally.
+# They plan to celebrate New Year's turn-over twice, one hour apart,
+# so it appears that the situation will last at least that long.
+# The Nunavut Intergovernmental Affairs hopes that they will "come to
+# their senses", but the locals evidently don't see any problem with
+# the current state of affairs.
+
+# From Michaela Rodrigue, writing in the
+# <a href="http://www.nunatsiaq.com/archives/nunavut991130/nvt91119_17.html">
+# Nunatsiaq News (1999-11-19)</a>:
+# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
+# central - or Nunavut time - for government offices, and eastern time
+# for municipal offices and schools.... Igloolik [was similar but then]
+# made the switch to central time on Saturday, Nov. 6.
+
+# From Paul Eggert (2000-10-02):
+# Matthews and Vincent (1998) say the following, but we lack histories
+# for these potential new Zones.
+#
+# The Canadian Forces station at Alert uses Eastern Time while the
+# handful of residents at the Eureka weather station [in the Central
+# zone] skip daylight savings. Baffin Island, which is crossed by the
+# Central, Eastern and Atlantic Time zones only uses Eastern Time.
+# Gjoa Haven, Taloyoak and Pelly Bay all use Mountain instead of
+# Central Time and Southampton Island [in the Central zone] is not
+# required to use daylight savings.
+
+# From
+# <a href="http://www.nunatsiaq.com/archives/nunavut001130/nvt21110_02.html">
+# Nunavut now has two time zones
+# </a> (2000-11-10):
+# The Nunavut government would allow its employees in Kugluktuk and
+# Cambridge Bay to operate on central time year-round, putting them
+# one hour behind the rest of Nunavut for six months during the winter.
+# At the end of October the two communities had rebelled against
+# Nunavut's unified time zone, refusing to shift to eastern time with
+# the rest of the territory for the winter. Cambridge Bay remained on
+# central time, while Kugluktuk, even farther west, reverted to
+# mountain time, which they had used before the advent of Nunavut's
+# unified time zone in 1999.
+#
+# From Rives McDow (2001-01-20), quoting the Nunavut government:
+# The preceding decision came into effect at midnight, Saturday Nov 4, 2000.
+
+# From Paul Eggert (2000-12-04):
+# Let's just keep track of the official times for now.
+
+# From Rives McDow (2001-03-07):
+# The premier of Nunavut has issued a ministerial statement advising
+# that effective 2001-04-01, the territory of Nunavut will revert
+# back to three time zones (mountain, central, and eastern). Of the
+# cities in Nunavut, Coral Harbor is the only one that I know of that
+# has said it will not observe dst, staying on EST year round. I'm
+# checking for more info, and will get back to you if I come up with
+# more.
+# [Also see <http://www.nunatsiaq.com/nunavut/nvt10309_06.html> (2001-03-09).]
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule NT_YK 1918 only - Apr 14 2:00 1:00 D
Rule NT_YK 1918 only - Oct 27 2:00 0 S
Rule NT_YK 1919 only - May 25 2:00 1:00 D
Rule NT_YK 1919 only - Nov 1 0:00 0 S
-Rule NT_YK 1942 only - Feb 9 2:00 1:00 D
+Rule NT_YK 1942 only - Feb 9 2:00 1:00 W
Rule NT_YK 1945 only - Sep 30 2:00 0 S
Rule NT_YK 1965 only - Apr lastSun 0:00 2:00 DD
Rule NT_YK 1965 only - Oct lastSun 2:00 0 S
Rule NT_YK 1987 max - Apr Sun>=1 2:00 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Pangnirtung -4:22:56 - LMT 1884
- -4:00 NT_YK A%sT
-Zone America/Iqaluit -4:33:52 - LMT 1884 # Frobisher Bay
- -5:00 NT_YK E%sT
+ -4:00 NT_YK A%sT 1995 Apr Sun>=1 2:00
+ -5:00 Canada E%sT 1999 Oct 31 2:00
+ -6:00 Canada C%sT 2000 Oct 29 2:00
+ -5:00 Canada E%sT
+Zone America/Iqaluit -4:33:52 - LMT 1884 # Frobisher Bay before 1987
+ -5:00 NT_YK E%sT 1999 Oct 31 2:00
+ -6:00 Canada C%sT 2000 Oct 29 2:00
+ -5:00 Canada E%sT
Zone America/Rankin_Inlet -6:08:40 - LMT 1884
- -6:00 NT_YK C%sT
+ -6:00 NT_YK C%sT 2000 Oct 29 2:00
+ -5:00 - EST 2001 Apr 1 3:00
+ -6:00 Canada C%sT
+Zone America/Cambridge_Bay -7:00:20 - LMT 1884
+ -7:00 NT_YK M%sT 1999 Oct 31 2:00
+ -6:00 Canada C%sT 2000 Oct 29 2:00
+ -5:00 - EST 2000 Nov 5 0:00
+ -6:00 - CST 2001 Apr 1 3:00
+ -7:00 Canada M%sT
Zone America/Yellowknife -7:37:24 - LMT 1884
-7:00 NT_YK M%sT
Zone America/Inuvik -8:54:00 - LMT 1884
# Mexico
-# From Guy Harris:
-# Rules are from the Official Airline Guide, Worldwide Edition, for 1987.
-# Rules prior to 1987 are unknown.
-# The comments in the OAG say "Only Ensenada, Mexicale, San Felipe and Tijuana
-# observe DST." This is presumably Baja California Norte, above 28th parallel,
-# as listed there; [there is also] "Baja California Sur and N. Pacific
-# Coast (States of Sinaloa and Sonora)."
-
-# From Bob Devine (1988-01-28):
-# The Federal District (where Mexico City is) has observed [DST] several
-# times but not recently.
-#
-# I don't where to drawn the line in the North Baja area. 28th latitude
-# sounds good -- but it may be higher (how far [d]o radio stations from
-# San Diego affect culture?).
+# From Paul Eggert (2001-03-05):
+# The Investigation and Analysis Service of the
+# Mexican Library of Congress (MLoC) has published a
+# <a href="http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/">
+# history of Mexican local time (in Spanish)
+# </a>.
#
-# The dates of DST probably go back to 1981. The rules are the same as
-# US's. This is going to be a headache for US presidential electi[o]n years!
-
-# From Arthur David Olson (1988-02-13)
-# Since the 1981 starting date is only "probable," we'll keep the 1987
-# starting date below.
-
-# From U. S. Naval Observatory (1989-01-19):
-# MEXICO BAJA CAL N 7 H BEHIND UTC BAJA CALIFORNIA SUR AND
-# MEXICO BAJA CAL N N. PACIFIC COAST (STATES
-# MEXICO BAJA CAL N OF SINALOA AND SONORA)
-# MEXICO BAJA CAL N 8 H BEHIND UTC ABOVE 28TH PARALLEL APR 3
-# MEXICO BAJA CAL N - OCT 29
-# MEXICO BAJA CAL N 7 H BEHIND UTC ABOVE 28TH PARALLEL APR 3
-# MEXICO BAJA CAL N - 0CT 29
-# MEXICO 6 H BEHIND UTC STATES OF DURANGO,
-# MEXICO COAHUILA, NUEVO LEON,
-# MEXICO TAMAULIPAS
-# MEXICO 5 H BEHIND UTC STATES OF DURANGO,
-# MEXICO COAHUILA, NUEVO LEON,
-# MEXICO TAMAULIPAS APR 3 - OCT 29
-# MEXICO 6 H BEHIND UTC GENERAL MEXICO, STATES OF
-# MEXICO CAMPECHE, QUINTANA ROO AND
-# MEXICO YUCATAN
-
-# From Arthur David Olson (1989-01-21):
-# April 3 fell on a Sunday in 1988; October 29 fell on a Sunday in 1989. Ahem.
-# USNO claims there should be four Mexican zones rather than three:
-# a zone that's GMT-8 with DST; a zone that's always GMT-7;
-# a zone that's GMT-6 with DST; and a zone that's always GMT-6.
-
-# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
-# Shanks also says there are four zones, but disagrees about the fourth.
-# Instead of GMT-6 with DST, he says there's GMT-8 without DST.
+# Here are the discrepancies between Shanks and the MLoC.
+# (In all cases we go with the MLoC.)
+# Shanks reports that Baja was at -8:00 in 1922/1923.
+# Shanks says the 1930 transition in Baja was 1930-11-16.
+# Shanks reports no DST during summer 1931.
+# Shanks reports a transition at 1032-03-30 23:00, not 1932-04-01.
+# Shanks does not report transitions for Baja in 1945 or 1948.
+# Shanks reports southern Mexico transitions on 1981-12-01, not 12-23.
+# Shanks says Quintana Roo switched to -6:00 on 1982-12-02, and to -5:00
+# on 1997-10-26 at 02:00.
+
+# From Gwillim Law (2001-02-20):
+# There are some other discrepancies between the Decrees page and the
+# tz database. I think they can best be explained by supposing that
+# the researchers who prepared the Decrees page failed to find some of
+# the relevant documents.
+
+# From Paul Eggert (2000-07-26):
+# Shanks gives 1942-04-01 instead of 1942-04-24, and omits the 1981
+# and 1988 DST experiments. Go with spin.com.mx.
# From Alan Perry <alan.perry@eng.sun.com> (1996-02-15):
# A guy from our Mexico subsidiary finally found the Presidential Decree
# outlining the timezone changes in Mexico.
-#
+#
# ------------- Begin Forwarded Message -------------
-#
+#
# I finally got my hands on the Official Presidential Decree that sets up the
# rules for the DST changes. The rules are:
-#
+#
# 1. The country is divided in 3 timezones:
# - Baja California Norte (the Mexico/BajaNorte TZ)
# - Baja California Sur, Nayarit, Sinaloa and Sonora (the Mexico/BajaSur TZ)
# - The rest of the country (the Mexico/General TZ)
-#
+#
# 2. From the first Sunday in April at 2:00 AM to the last Sunday in October
# at 2:00 AM, the times in each zone are as follows:
# BajaNorte: GMT+7
# BajaSur: GMT+6
# General: GMT+5
-#
+#
# 3. The rest of the year, the times are as follows:
# BajaNorte: GMT+8
# BajaSur: GMT+7
# General: GMT+6
-#
+#
# The Decree was published in Mexico's Official Newspaper on January 4th.
-#
+#
# -------------- End Forwarded Message --------------
# From Paul Eggert (1996-06-12):
-# For an English translation of the decree,
-# see ``Diario Oficial: Time Zone Changeover'',
-# <URL:http://mexico-travel.com/extra/timezone_eng.html> (1996-01-04).
+# For an English translation of the decree, see
+# <a href="http://mexico-travel.com/extra/timezone_eng.html">
+# ``Diario Oficial: Time Zone Changeover'' (1996-01-04).
+# </a>
+
+# From Rives McDow (1998-10-08):
+# The State of Quintana Roo has reverted back to central STD and DST times
+# (i.e. UTC -0600 and -0500 as of 1998-08-02).
+
+# From Rives McDow (2000-01-10):
+# Effective April 4, 1999 at 2:00 AM local time, Sonora changed to the time
+# zone 5 hours from the International Date Line, and will not observe daylight
+# savings time so as to stay on the same time zone as the southern part of
+# Arizona year round.
+
+# From Jesper Norgaard, translating
+# <http://www.reforma.com/nacional/articulo/064327/> (2001-01-17):
+# In Oaxaca, the 55.000 teachers from the Section 22 of the National
+# Syndicate of Education Workers, refuse to apply daylight saving each
+# year, so that the more than 10,000 schools work at normal hour the
+# whole year.
+
+# From Gwillim Law (2001-01-19):
+# <http://www.reforma.com/negocios_y_dinero/articulo/064481/> ... says
+# (translated):...
+# January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
+# that Summer Time will be reduced from seven to five months, starting
+# this year....
+# <http://www.publico.com.mx/scripts/texto3.asp?action=pagina&pag=21&pos=p&secc=naci&date=01/17/2001>
+# [translated], says "summer time will ... take effect on the first Sunday
+# in May, and end on the last Sunday of September.
+
+# From Arthur David Olson (2001-01-25):
+# The 2001-01-24 traditional Washington Post contained the page one
+# story "Timely Issue Divides Mexicans."...
+# http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
+# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
+# Mexico City and its 20 million residents on a different time than
+# the rest of the country..." In particular, Lopez Obrador would abolish
+# observation of Daylight Saving Time.
+
+# <a href="http://www.conae.gob.mx/ahorro/decretohorver2001.html#decre">
+# Official statute published by the Energy Department
+# </a> (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
+# and Sonora with no DST. This was reported by Jesper Norgaard (2001-02-03).
+
+# From Paul Eggert (2001-03-03):
+#
+# <a href="http://www.latimes.com/news/nation/20010303/t000018766.html">
+# James F. Smith writes in today's LA Times
+# </a>
+# * Sonora will continue to observe standard time.
+# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
+# the Federal District will not adopt DST.
+# * 4 of 16 district leaders announced they'll ignore the decree.
+# * The decree does not affect federal-controlled facilities including
+# the airport, banks, hospitals, and schools.
+#
+# For now we'll assume that the Federal District will bow to federal rules.
+
+# From Jesper Norgaard (2001-04-01):
+# I found some references to the Mexican application of daylight
+# saving, which modifies what I had already sent you, stating earlier
+# that a number of northern Mexican states would go on daylight
+# saving. The modification reverts this to only cover Baja California
+# (Norte), while all other states (except Sonora, who has no daylight
+# saving all year) will follow the original decree of president
+# Vicente Fox, starting daylight saving May 6, 2001 and ending
+# September 30, 2001.
+# References: "Diario de Monterrey" <www.diariodemonterrey.com/index.asp>
+# Palabra <http://palabra.infosel.com/010331/primera/ppri3101.pdf> (2001-03-31)
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Mexico 1939 only - Feb 5 0:00 1:00 D
Rule Mexico 1939 only - Jun 25 0:00 0 S
Rule Mexico 1940 only - Dec 9 0:00 1:00 D
Rule Mexico 1941 only - Apr 1 0:00 0 S
-Rule Mexico 1943 only - Dec 16 0:00 1:00 D
+Rule Mexico 1943 only - Dec 16 0:00 1:00 W
Rule Mexico 1944 only - May 1 0:00 0 S
Rule Mexico 1950 only - Feb 12 0:00 1:00 D
Rule Mexico 1950 only - Jul 30 0:00 0 S
-Rule Mexico 1996 max - Apr Sun>=1 2:00 1:00 D
-Rule Mexico 1996 max - Oct lastSun 2:00 0 S
-#
-Rule BajaN 1950 1966 - Apr lastSun 2:00 1:00 D
-Rule BajaN 1950 1961 - Sep lastSun 2:00 0 S
-Rule BajaN 1961 1966 - Oct lastSun 2:00 0 S
+Rule Mexico 1996 2000 - Apr Sun>=1 2:00 1:00 D
+Rule Mexico 1996 2000 - Oct lastSun 2:00 0 S
+Rule Mexico 2001 max - May Sun>=1 2:00 1:00 D
+Rule Mexico 2001 max - Sep lastSun 2:00 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
+# Quintana Roo
+Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 0:12:56
+ -6:00 - CST 1981 Dec 23
+ -5:00 Mexico E%sT 1998 Aug 2 2:00
+ -6:00 Mexico C%sT
+# Campeche, Yucatan
+Zone America/Merida -5:58:28 - LMT 1922 Jan 1 0:01:32
+ -6:00 - CST 1981 Dec 23
+ -5:00 - EST 1982 Dec 2
+ -6:00 Mexico C%sT
+# Coahuila, Durango, Nuevo Leon, Tamaulipas
+Zone America/Monterrey -6:41:16 - LMT 1921 Dec 31 23:18:44
+ -6:00 - CST 1988
+ -6:00 US C%sT 1989
+ -6:00 Mexico C%sT
+# Central Mexico
Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 0:23:24
-7:00 - MST 1927 Jun 10 23:00
-6:00 - CST 1930 Nov 15
-7:00 - MST 1931 May 1 23:00
-6:00 - CST 1931 Oct
- -7:00 - MST 1932 Mar 30 23:00
+ -7:00 - MST 1932 Apr 1
-6:00 Mexico C%sT
+# Chihuahua
+Zone America/Chihuahua -7:04:20 - LMT 1921 Dec 31 23:55:40
+ -7:00 - MST 1927 Jun 10 23:00
+ -6:00 - CST 1930 Nov 15
+ -7:00 - MST 1931 May 1 23:00
+ -6:00 - CST 1931 Oct
+ -7:00 - MST 1932 Apr 1
+ -6:00 - CST 1996
+ -6:00 Mexico C%sT 1998
+ -6:00 - CST 1998 Apr Sun>=1 3:00
+ -7:00 Mexico M%sT
+# Sonora
+Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08
+ -7:00 - MST 1927 Jun 10 23:00
+ -6:00 - CST 1930 Nov 15
+ -7:00 - MST 1931 May 1 23:00
+ -6:00 - CST 1931 Oct
+ -7:00 - MST 1932 Apr 1
+ -6:00 - CST 1942 Apr 24
+ -7:00 - MST 1949 Jan 14
+ -8:00 - PST 1970
+ -7:00 Mexico M%sT 1999
+ -7:00 - MST
+# Baja California Sur, Nayarit, Sinaloa
Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20
-7:00 - MST 1927 Jun 10 23:00
-6:00 - CST 1930 Nov 15
-7:00 - MST 1931 May 1 23:00
-6:00 - CST 1931 Oct
- -7:00 - MST 1932 Mar 30 23:00
- -6:00 - CST 1942 Apr
+ -7:00 - MST 1932 Apr 1
+ -6:00 - CST 1942 Apr 24
-7:00 - MST 1949 Jan 14
-8:00 - PST 1970
-7:00 Mexico M%sT
+# Baja California
Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56
+ -7:00 - MST 1924
-8:00 - PST 1927 Jun 10 23:00
- -7:00 - MST 1930 Nov 16
- -8:00 - PST 1942 Apr
- -7:00 - MST 1949 Jan 14
- -8:00 BajaN P%sT 1967 Apr lastSun 2:00
+ -7:00 - MST 1930 Nov 15
+ -8:00 - PST 1931 Apr 1
+ -8:00 1:00 PDT 1931 Sep 30
+ -8:00 - PST 1942 Apr 24
+ -8:00 1:00 PWT 1945 Nov 12
+ -8:00 - PST 1948 Apr 5
+ -8:00 1:00 PDT 1949 Jan 14
+ -8:00 - PST 1954
+ -8:00 CA P%sT 1961
+ -8:00 - PST 1976
-8:00 US P%sT 1996
- -8:00 Mexico P%sT
-Zone America/Ensenada -7:46:28 - LMT 1922 Jan 1 0:13:32
- -8:00 - PST 1927 Jun 10 23:00
- -7:00 - MST 1930 Nov 16
- -8:00 - PST 1942 Apr
- -7:00 - MST 1949 Jan 14
- -8:00 - PST 1996
- -8:00 Mexico P%sT
+ -8:00 Mexico P%sT 2001
+ -8:00 US P%sT
+# From Paul Eggert (2001-03-05):
+# Formerly there was an America/Ensenada zone, which differed from
+# America/Tijuana only in that it did not observe DST from 1976
+# through 1995. This was as per Shanks. However, Guy Harris reports
+# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
+# Tijuana observe DST," which contradicts Shanks but does imply that
+# DST-observance was a town-by-town matter back then. This concerns
+# data after 1970 so most likely there should be at least one Zone
+# other than America/Tijuana for Baja, but it's not clear yet what its
+# name or contents should be.
#
# Revillagigedo Is
# no information
Rule Barb 1980 only - Sep 25 2:00 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Barbados -3:58:28 - LMT 1924 # Bridgetown
- -3:58 - BMT 1932 # Bridgetown Mean Time
+ -3:58:28 - BMT 1932 # Bridgetown Mean Time
-4:00 Barb A%sT
# Belize
# Cayman Is
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Cayman -5:25:32 - LMT 1890 # Georgetown
- -5:07 - KMT 1912 Feb # Kingston Mean Time
+ -5:07:12 - KMT 1912 Feb # Kingston Mean Time
-5:00 - EST
-# Clipperton
-# uninhabited
-
# Costa Rica
-# Shanks gives some very odd dates for 1991, and stops there.
-# For now, we won't guess further.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule CR 1979 1980 - Feb lastSun 0:00 1:00 D
Rule CR 1979 1980 - Jun Sun>=1 0:00 0 S
# There are too many San Joses elsewhere, so we'll use `Costa Rica'.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Costa_Rica -5:36:20 - LMT 1890 # San Jose
- -5:36 - SJMT 1921 Jan 15 # San Jose Mean Time
+ -5:36:20 - SJMT 1921 Jan 15 # San Jose Mean Time
-6:00 CR C%sT
# Coco
# no information; probably like America/Costa_Rica
# Cuba
-# From Bob Devine (1988-01-28):
-# . . .DST is from 2nd Sunday in May to 2nd Sunday in October since 1981.
-# Change at midnight. In 1979 & 1980, started at 3rd Sunday in March
-# (I think).
-
-# From U. S. Naval Observatory (1989-01-19):
-# CUBA 5 H BEHIND UTC
-# CUBA 4 H BEHIND UTC MAR 20 - OCT 8
+# From Arthur David Olson (1999-03-29):
+# The 1999-03-28 exhibition baseball game held in Havana, Cuba, between
+# the Cuban National Team and the Baltimore Orioles was carried live on
+# the Orioles Radio Network, including affiliate WTOP in Washington, DC.
+# During the game, play-by-play announcer Jim Hunter noted that
+# "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
+# Time today." (The "two hour" remark referred to losing one hour of
+# sleep on 1999-03-28--when the announcers were in Cuba as it switched
+# to DST--and one more hour on 1999-04-04--when the announcers will have
+# returned to Baltimore, which switches on that date.)
-# From Shanks (1991):
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Cuba 1928 only - Jun 10 0:00 1:00 D
Rule Cuba 1928 only - Oct 10 0:00 0 S
Rule Cuba 1972 1974 - Oct 8 0:00 0 S
Rule Cuba 1975 1977 - Oct lastSun 0:00 0 S
Rule Cuba 1978 only - May 7 0:00 1:00 D
-Rule Cuba 1978 1980 - Oct Sun>=8 0:00 0 S
+Rule Cuba 1978 1990 - Oct Sun>=8 0:00 0 S
Rule Cuba 1979 1980 - Mar Sun>=15 0:00 1:00 D
Rule Cuba 1981 1985 - May Sun>=5 0:00 1:00 D
-Rule Cuba 1981 1990 - Oct Sun>=8 0:00 0 S
Rule Cuba 1986 1989 - Mar Sun>=14 0:00 1:00 D
-Rule Cuba 1990 max - Apr Sun>=1 0:00 1:00 D
+Rule Cuba 1990 1997 - Apr Sun>=1 0:00 1:00 D
Rule Cuba 1991 1995 - Oct Sun>=8 0:00s 0 S
-Rule Cuba 1996 max - Oct Sun>=1 0:00s 0 S
+Rule Cuba 1996 only - Oct 6 0:00s 0 S
+Rule Cuba 1997 only - Oct 12 0:00s 0 S
+Rule Cuba 1998 1999 - Mar lastSun 0:00s 1:00 D
+Rule Cuba 1998 max - Oct lastSun 0:00s 0 S
+Rule Cuba 2000 max - Apr Sun>=1 0:00s 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Havana -5:29:28 - LMT 1890
- -5:30 - HMT 1925 Jul 19 12:00 # Havana MT
+ -5:29:36 - HMT 1925 Jul 19 12:00 # Havana MT
-5:00 Cuba C%sT
# Dominica
-4:00 - AST
# Dominican Republic
+
+# From Steffen Thorsen (2000-10-30):
+# Enrique Morales reported to me that the Dominican Republic has changed the
+# time zone to Eastern Standard Time as of Sunday 29 at 2 am....
+# http://www.listin.com.do/antes/261000/republica/princi.html
+
+# From Paul Eggert (2000-12-04):
+# That URL (2000-10-26, in Spanish) says they planned to use US-style DST.
+
+# From Rives McDow (2000-12-01):
+# Dominican Republic changed its mind and presidential decree on Tuesday,
+# November 28, 2000, with a new decree. On Sunday, December 3 at 1:00 AM the
+# Dominican Republic will be reverting to 8 hours from the International Date
+# Line, and will not be using DST in the foreseeable future. The reason they
+# decided to use DST was to be in synch with Puerto Rico, who was also going
+# to implement DST. When Puerto Rico didn't implement DST, the president
+# decided to revert.
+
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule DR 1966 only - Oct 30 0:00 1:00 D
Rule DR 1967 only - Feb 28 0:00 0 S
Zone America/Santo_Domingo -4:39:36 - LMT 1890
-4:40 - SDMT 1933 Apr 1 12:00 # S. Dom. MT
-5:00 DR E%sT 1974 Oct 27
+ -4:00 - AST 2000 Oct 29 02:00
+ -5:00 US E%sT 2000 Dec 3 01:00
-4:00 - AST
# El Salvador
Rule Haiti 1983 only - May 8 0:00 1:00 D
Rule Haiti 1984 1987 - Apr lastSun 0:00 1:00 D
Rule Haiti 1983 1987 - Oct lastSun 0:00 0 S
-# Shanks says AT is 2:00, but IATA SSIM (1991/1996) says 1:00s. Go with IATA.
-Rule Haiti 1988 max - Apr Sun>=1 1:00s 1:00 D
-Rule Haiti 1988 max - Oct lastSun 1:00s 0 S
+# Shanks says AT is 2:00, but IATA SSIM (1991/1997) says 1:00s. Go with IATA.
+Rule Haiti 1988 1997 - Apr Sun>=1 1:00s 1:00 D
+Rule Haiti 1988 1997 - Oct lastSun 1:00s 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Port-au-Prince -4:49:20 - LMT 1890
-4:49 - PPMT 1917 Jan 24 12:00 # P-a-P MT
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Tegucigalpa -5:48:52 - LMT 1921 Apr
-6:00 Salv C%sT
+#
+# Great Swan I ceded by US to Honduras in 1972
# Jamaica
# From U. S. Naval Observatory (1989-01-19):
# JAMAICA 5 H BEHIND UTC
-# From Shanks (1991):
+# From Shanks:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Jamaica -5:07:12 - LMT 1890 # Kingston
- -5:07 - KMT 1912 Feb # Kingston Mean Time
- -5:00 - EST 1974 Jan 6 2:00
+ -5:07:12 - KMT 1912 Feb # Kingston Mean Time
+ -5:00 - EST 1974 Apr 28 2:00
-5:00 US E%sT 1984
-5:00 - EST
-4:00 - AST
# Montserrat
+# From Paul Eggert (1997-08-31):
+# Recent volcanic eruptions have forced evacuation of Plymouth, the capital.
+# Luckily, Olveston, the current de facto capital, has the same longitude.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone America/Montserrat -4:08:52 - LMT 1911 Jul 1 0:01 # Plymouth
+Zone America/Montserrat -4:08:52 - LMT 1911 Jul 1 0:01 # Olveston
-4:00 - AST
# Nicaragua
+#
+# From Steffen Thorsen (1998-12-29):
+# Nicaragua seems to be back at -6:00 but I have not been able to find when
+# they changed from -5:00.
+#
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Nic 1979 1980 - Mar Sun>=16 0:00 1:00 D
Rule Nic 1979 1980 - Jun Mon>=23 0:00 0 S
-6:00 - CST 1973 May
-5:00 - EST 1975 Feb 16
-6:00 Nic C%sT 1993 Jan 1 4:00
- -5:00 - EST
+ -5:00 - EST 1998 Dec
+ -6:00 - CST
# Panama
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# St Vincent and the Grenadines
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/St_Vincent -4:04:56 - LMT 1890 # Kingstown
- -4:05 - KMT 1912 # Kingstown Mean Time
+ -4:04:56 - KMT 1912 # Kingstown Mean Time
-4:00 - AST
# Turks and Caicos
-# From Paul Eggert (1996-11-22):
-# Shanks says they use US DST rules, but IATA SSIM (1991/1996)
+# From Paul Eggert (1998-08-06):
+# Shanks says they use US DST rules, but IATA SSIM (1991/1998)
# says they switch at midnight. Go with IATA SSIM.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule TC 1979 1986 - Apr lastSun 0:00 1:00 D
Rule TC 1987 max - Apr Sun>=1 0:00 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Grand_Turk -4:44:32 - LMT 1890
- -5:07 - KMT 1912 Feb # Kingston Mean Time
+ -5:07:12 - KMT 1912 Feb # Kingston Mean Time
-5:00 TC E%sT
# British Virgin Is
-# $OpenBSD: southamerica,v 1.4 1997/01/14 04:36:57 millert Exp $
-# @(#)southamerica 7.16
+# @(#)southamerica 7.40
+
+# $FreeBSD: src/share/zoneinfo/southamerica,v 1.16 2001/04/06 16:46:52 wollman Exp $
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
# tz@elsie.nci.nih.gov for general use in the future).
-# From Paul Eggert <eggert@twinsun.com> (1996-11-22):
+# From Paul Eggert <eggert@twinsun.com> (1999-07-07):
# A good source for time zone historical data outside the U.S. is
-# Thomas G. Shanks, The International Atlas (3rd edition),
-# San Diego: ACS Publications, Inc. (1991).
+# Thomas G. Shanks, The International Atlas (5th edition),
+# San Diego: ACS Publications, Inc. (1999).
#
-# Gwillim Law <LAW@encmail.encompass.com> writes that a good source
+# Gwillim Law <Gwil_Law@bridge-point.com> writes that a good source
# for recent time zone data is the International Air Transport
# Association's Standard Schedules Information Manual (IATA SSIM),
# published semiannually. Law sent in several helpful summaries
# Except where otherwise noted, Shanks is the source for entries through 1990,
# and IATA SSIM is the source for entries after 1990.
#
-# The following abbreviations are used in this file.
-# Corrections are welcome!
-# std dst
-# LMT Local Mean Time
-# -2:00 FST FDT Fernando de Noronha
-# -3:00 EST EDT Eastern Brazil
-# -4:00 WST WDT Western Brazil
-# -4:00 AST ADT Atlantic
-# -5:00 AST ADT Acre
-#
-# See the `africa' file for time zone naming and abbreviation conventions.
# Earlier editions of these tables used the North American style (e.g. ARST and
# ARDT for Argentine Standard and Daylight Time), but the following quote
# suggests that it's better to use European style (e.g. ART and ARST).
# in Europe and South America.
# -- E O Cutler, _New York Times_ (1937-02-14), quoted in
# H L Mencken, _The American Language: Supplement I_ (1960), p 466
-
-
-# From Guy Harris:
-# From Official Airline Guide - Worldwide Edition (1987). Countries not
-# listed here do not observe DST, according to the OAG. Time zone names
-# are pure inventions, and none are supplied for countries not observing
-# DST; updates from natives would be appreciated. The times that DST
-# starts and ends are based on the assumption that they switch a 2AM just
-# as everybody else does.
+#
+# Earlier editions of these tables also used the North American style
+# for time zones in Brazil, but this was incorrect, as Brazilians say
+# "summer time". Reinaldo Goulart, a Sao Paulo businessman active in
+# the railroad sector, writes (1999-07-06):
+# The subject of time zones is currently a matter of discussion/debate in
+# Brazil. Let's say that "the Brasilia time" is considered the
+# "official time" because Brasilia is the capital city.
+# The other three time zones are called "Brasilia time "minus one" or
+# "plus one" or "plus two". As far as I know there is no such
+# name/designation as "Eastern Time" or "Central Time".
+# So I invented the following (English-language) abbreviations for now.
+# Corrections are welcome!
+# std dst
+# -2:00 FNT FNST Fernando de Noronha
+# -3:00 BRT BRST Brasilia
+# -4:00 AMT AMST Amazon
+# -5:00 ACT ACST Acre
###############################################################################
Rule Arg 1964 1966 - Mar 1 0:00 0 -
Rule Arg 1964 1966 - Oct 15 0:00 1:00 S
Rule Arg 1967 only - Apr 1 0:00 0 -
-Rule Arg 1967 1968 - Oct Sun<=7 0:00 1:00 S
-Rule Arg 1968 1969 - Apr Sun<=7 0:00 0 -
+Rule Arg 1967 1968 - Oct Sun>=1 0:00 1:00 S
+Rule Arg 1968 1969 - Apr Sun>=1 0:00 0 -
Rule Arg 1974 only - Jan 23 0:00 1:00 S
Rule Arg 1974 only - May 1 0:00 0 -
-Rule Arg 1974 1976 - Oct Sun<=7 0:00 1:00 S
-Rule Arg 1975 1977 - Apr Sun<=7 0:00 0 -
+Rule Arg 1974 1976 - Oct Sun>=1 0:00 1:00 S
+Rule Arg 1975 1977 - Apr Sun>=1 0:00 0 -
Rule Arg 1985 only - Nov 2 0:00 1:00 S
Rule Arg 1986 only - Mar 14 0:00 0 -
Rule Arg 1986 1987 - Oct 25 0:00 1:00 S
# Talleres de Hidrografia Naval Argentina
# (Argentine Naval Hydrography Institute)
#
-# Shanks gives 1989 Mar 16 and stops after 1990 Mar 4; go with Otero.
+# Shanks stops after 1992-03-01; go with Otero.
Rule Arg 1989 1993 - Mar Sun>=1 0:00 0 -
Rule Arg 1989 1992 - Oct Sun>=15 0:00 1:00 S
#
# time corrections was derogated and no more modifications
# to the time zones (for daylight saving) are now made.
#
+# From Rives McDow (2000-01-10):
+# On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
+# which did not result in the switch of a time zone, as they stayed 9 hours
+# from the International Date Line.
+Rule Arg 1999 only - Oct Sun>=1 0:00 1:00 S
+Rule Arg 2000 only - Mar Sun>=1 0:00 0 -
+#
+# From Peter Gradelski via Steffen Thorsen (2000-03-01):
+# We just checked with our Sao Paulo office and they say the government of
+# Argentina decided not to become one of the countries that go on or off DST.
+# So Buenos Aires should be -3 hours from GMT at all times.
+#
+# From Fabian L. Arce Jofre <farcejofre@bigfoot.com> (2000-04-04):
+# The law that claimed DST for Argentina was derogated by President Fernando
+# de la Rua on March 2, 2000, because it would make people spend more energy
+# in the winter time, rather than less. The change took effect on March 3.
+#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
#
-# Buenos Aires (BA), Distrito Federal (DF), Santa Cruz (SC),
-# Tierra del Fuego (TF) & Antartida e Islas
+# Buenos Aires (BA), Capital Federal (CF), Santa Cruz (SC),
+# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
Zone America/Buenos_Aires -3:53:48 - LMT 1894 Nov
-4:16:44 - CMT 1920 May # Cordoba Mean Time
-4:00 - ART 1930 Dec
- -4:00 Arg AR%sT 1969 Oct 5
- -3:00 Arg AR%sT
+ -4:00 Arg AR%sT 1969 Oct 5
+ -3:00 Arg AR%sT 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
+ -3:00 - ART
#
# Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN), Chaco (CC),
# Formosa (FM), La Pampa (LP), Chubut (CH)
Zone America/Rosario -4:02:40 - LMT 1894 Nov
-4:16:44 - CMT 1920 May
-4:00 - ART 1930 Dec
- -4:00 Arg AR%sT 1969 Oct 5
+ -4:00 Arg AR%sT 1969 Oct 5
-3:00 Arg AR%sT 1991 Jul
+ -3:00 - ART 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
-3:00 - ART
#
# Cordoba (CB), Santiago del Estero (SE), Salta (SA), Tucuman (TM), La Rioja (LR), San Juan (SJ), San Luis (SL),
Zone America/Cordoba -4:16:44 - LMT 1894 Nov
-4:16:44 - CMT 1920 May
-4:00 - ART 1930 Dec
- -4:00 Arg AR%sT 1969 Oct 5
+ -4:00 Arg AR%sT 1969 Oct 5
-3:00 Arg AR%sT 1990 Jul
+ -3:00 - ART 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
-3:00 - ART
#
# Jujuy (JY)
-4:00 - WART 1991 Oct 6
-4:00 1:00 WARST 1992 Mar 15
-4:00 - WART 1992 Oct 18
+ -3:00 - ART 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
-3:00 - ART
#
# Catamarca (CT)
Zone America/Catamarca -4:23:08 - LMT 1894 Nov
-4:16:44 - CMT 1920 May
-4:00 - ART 1930 Dec
- -4:00 Arg AR%sT 1969 Oct 5
+ -4:00 Arg AR%sT 1969 Oct 5
-3:00 Arg AR%sT 1990 Jul
-3:00 - ART 1991 Jul
-3:00 Arg AR%sT 1992 Jul
+ -3:00 - ART 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
-3:00 - ART
#
# Mendoza (MZ)
-4:00 - WART 1991 Oct 15
-4:00 1:00 WARST 1992 Mar 1
-4:00 - WART 1992 Oct 18
+ -3:00 - ART 1999 Oct 3 0:00
+ -4:00 Arg AR%sT 2000 Mar 3 0:00
-3:00 - ART
# Aruba
# Brazil
-# From Guy Harris:
-# The OAG lists 1987-10-25 and 1988-02-12 as the starting and
-# ending dates, giving them as "estimated date(s) based on previous year". We
-# infer a rule here from one example, always a dangerous practice.... Yes,
-# they really do switch on Saturday, according to the OAG.
-# "[America/Porto_Acre]" is for the Territory of Acre;
-# "[America/Noronha]" is for Fernando De Noronha.
-
# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
# The mayor of Rio recently attempted to change the time zone rules
# just in his city, in order to leave more summer time for the tourist trade.
# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
-# From Paul Eggert (1996-11-22):
-# Let's make the following assumptions:
+# From Marcos Tadeu (1998-09-27):
+# <a href="http://pcdsh01.on.br/verao1.html">
+# Brazilian official page
+# </a>
+
+# From Jesper Norgaard (2000-11-03):
+# [For an official list of which regions in Brazil use which time zones, see:]
+# http://pcdsh01.on.br/Fusbr.htm
+# http://pcdsh01.on.br/Fusbrhv.htm
+
+# From Paul Eggert (2000-10-02):
+# The official decrees referenced below are taken from
+# <a href="http://pcdsh01.on.br/DecHV.html">
+# Decretos sobre o Horario de Verao no Brasil
+# </a> (1999-10-04, in Portuguese).
+# The official site for all decrees, including those not related to time, is
+# <a href="http://www.presidencia.gov.br/CCIVIL/decreto/principal_ano.htm">
+# Presidencia da Republica, Subchefia para Assuntos Juridicos, Decretos
+# </a> (in Portuguese).
+
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+# Decree <a href="http://pcdsh01.on.br/HV20466.htm">20,466</a> (1931-10-01)
+# Decree <a href="http://pcdsh01.on.br/HV21896.htm">21,896</a> (1932-01-10)
+Rule Brazil 1931 only - Oct 3 11:00 1:00 S
+Rule Brazil 1932 1933 - Apr 1 0:00 0 -
+Rule Brazil 1932 only - Oct 3 0:00 1:00 S
+# Decree <a href="http://pcdsh01.on.br/HV23195.htm">23,195</a> (1933-10-10)
+# revoked DST.
+# Decree <a href="http://pcdsh01.on.br/HV27496.htm">27,496</a> (1949-11-24)
+# Decree <a href="http://pcdsh01.on.br/HV27998.htm">27,998</a> (1950-04-13)
+Rule Brazil 1949 1952 - Dec 1 0:00 1:00 S
+Rule Brazil 1950 only - Apr 16 1:00 0 -
+Rule Brazil 1951 1952 - Apr 1 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV32308.htm">32,308</a> (1953-02-24)
+Rule Brazil 1953 only - Mar 1 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV34724.htm">34,724</a> (1953-11-30)
+# revoked DST.
+# Decree <a href="http://pcdsh01.on.br/HV52700.htm">52,700</a> (1963-10-18)
+# established DST from 1963-10-23 00:00 to 1964-02-29 00:00
+# in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
+# Decree <a href="http://pcdsh01.on.br/HV53071.htm">53,071</a> (1963-12-03)
+# extended the above decree to all of the national territory on 12-09.
+Rule Brazil 1963 only - Dec 9 0:00 1:00 S
+# Decree <a href="http://pcdsh01.on.br/HV53604.htm">53,604</a> (1964-02-25)
+# extended summer time by one day to 1964-03-01 00:00 (start of school).
+Rule Brazil 1964 only - Mar 1 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV55639.htm">55,639</a> (1965-01-27)
+Rule Brazil 1965 only - Jan 31 0:00 1:00 S
+Rule Brazil 1965 only - Mar 31 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV57303.htm">57,303</a> (1965-11-22)
+Rule Brazil 1965 only - Dec 1 0:00 1:00 S
+# Decree <a href="http://pcdsh01.on.br/HV57843.htm">57,843</a> (1966-02-18)
+Rule Brazil 1966 1968 - Mar 1 0:00 0 -
+Rule Brazil 1966 1967 - Nov 1 0:00 1:00 S
+# Decree <a href="http://pcdsh01.on.br/HV63429.htm">63,429</a> (1968-10-15)
+# revoked DST.
+# Decree <a href="http://pcdsh01.on.br/HV91698.htm">91,698</a> (1985-09-27)
+Rule Brazil 1985 only - Nov 2 0:00 1:00 S
+# Decree 92,310 (1986-01-21)
+# Decree 92,463 (1986-03-13)
+Rule Brazil 1986 only - Mar 15 0:00 0 -
+# Decree 93,316 (1986-10-01)
+Rule Brazil 1986 only - Oct 25 0:00 1:00 S
+Rule Brazil 1987 only - Feb 14 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV94922.htm">94,922</a> (1987-09-22)
+Rule Brazil 1987 only - Oct 25 0:00 1:00 S
+Rule Brazil 1988 only - Feb 7 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV96676.htm">96,676</a> (1988-09-12)
+# except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
+Rule Brazil 1988 only - Oct 16 0:00 1:00 S
+Rule Brazil 1989 only - Jan 29 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV98077.htm">98,077</a> (1989-08-21)
+# with the same exceptions
+Rule Brazil 1989 only - Oct 15 0:00 1:00 S
+Rule Brazil 1990 only - Feb 11 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV99530.htm">99,530</a> (1990-09-17)
+# adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
+# Decree 99,629 (1990-10-19) adds BA, MT.
+Rule Brazil 1990 only - Oct 21 0:00 1:00 S
+Rule Brazil 1991 only - Feb 17 0:00 0 -
+# <a href="http://pcdsh01.on.br/HV1991.htm">Unnumbered decree</a> (1991-09-25)
+# adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
+Rule Brazil 1991 only - Oct 20 0:00 1:00 S
+Rule Brazil 1992 only - Feb 9 0:00 0 -
+# <a href="http://pcdsh01.on.br/HV1992.htm">Unnumbered decree</a> (1992-10-16)
+# adopted by same states.
+Rule Brazil 1992 only - Oct 25 0:00 1:00 S
+Rule Brazil 1993 only - Jan 31 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV942.htm">942</a> (1993-09-28)
+# adopted by same states, plus AM.
+# Decree <a href="http://pcdsh01.on.br/HV1252.htm">1,252</a> (1994-09-22)
+# adopted by same states, minus AM.
+# Decree <a href="http://pcdsh01.on.br/HV1636.htm">1,636</a> (1995-09-14)
+# adopted by same states, plus TO.
+# Decree <a href="http://pcdsh01.on.br/HV1674.htm">1,674</a> (1995-10-13)
+# adds AL, SE.
+Rule Brazil 1993 1995 - Oct Sun>=11 0:00 1:00 S
+Rule Brazil 1994 1995 - Feb Sun>=15 0:00 0 -
+Rule Brazil 1996 only - Feb 11 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/HV2000.htm">2,000</a> (1996-09-04)
+# adopted by same states, minus AL, SE.
+Rule Brazil 1996 only - Oct 6 0:00 1:00 S
+Rule Brazil 1997 only - Feb 16 0:00 0 -
+# From Daniel C. Sobral <dcs@gns.com.br> (1998-02-12):
+# In 1997, the DS began on October 6. The stated reason was that
+# because international television networks ignored Brazil's policy on DS,
+# they bought the wrong times on satellite for coverage of Pope's visit.
+# This year, the ending date of DS was postponed to March 1
+# to help dealing with the shortages of electric power.
#
-# * All data in Shanks are correct through 1990. In particular,
-# Shanks was right when he said Acre stopped observing DST in mid-1988.
-# * Areas where Shanks reports DST up to 1990, but the IATA reports no DST
-# in 1995, stopped observing DST in mid-1990.
+# From Paul Eggert (1998-02-25):
+# <a href="http://churchnet.ucsm.ac.uk/news/files2/news165.htm">
+# Brazil Prepares for Papal Visit
+# </a>,
+# Church Net UK (1997-10-02).
#
-# Under these assumptions Brazil needs 7 entries to cover all the distinct
-# time zone histories since 1970:
+# Decree 2,317 (1997-09-04), adopted by same states.
+Rule Brazil 1997 only - Oct 6 0:00 1:00 S
+# Decree <a href="http://pcdsh01.on.br/figuras/HV2495.JPG">2,495</a>
+# (1998-02-10)
+Rule Brazil 1998 only - Mar 1 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/figuras/Hv98.jpg">2,780</a> (1998-09-11)
+# adopted by the same states as before.
+Rule Brazil 1998 only - Oct 11 0:00 1:00 S
+Rule Brazil 1999 only - Feb 21 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/figuras/HV3150.gif">3,150</a>
+# (1999-08-23) adopted by same states.
+# Decree <a href="http://pcdsh01.on.br/DecHV99.gif">3,188</a> (1999-09-30)
+# adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
+Rule Brazil 1999 only - Oct 3 0:00 1:00 S
+Rule Brazil 2000 only - Feb 27 0:00 0 -
+# Decree <a href="http://pcdsh01.on.br/DEC3592.htm">3,592</a> (2000-09-06)
+# adopted by the same states as before.
+# Decree <a href="http://pcdsh01.on.br/Dec3630.jpg">3,630</a> (2000-10-13)
+# repeals DST in PE and RR, effective 2000-10-15 00:00.
+# Decree <a href="http://pcdsh01.on.br/Dec3632.jpg">3,632</a> (2000-10-17)
+# repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
#
-# Noronha (UTC-2), Fortaleza (UTC-3), and Manaus (UTC-4) stopped observing DST
-# in mid-1990.
-# Maceio (UTC-3) stopped observing DST in mid-1990, but started again mid-1995.
-# Sao Paulo (UTC-3) and Cuiaba (UTC-4) always observed DST.
-# Porto Acre (UTC-5) stopped observing DST in mid-1988.
+# These give only one year's rules. After that, the rules are guesses
+# and are quite possibly wrong, but are more likely than no DST at all.
+Rule Brazil 2000 max - Oct Sun>=8 0:00 1:00 S
+Rule Brazil 2001 max - Feb Sun>=15 0:00 0 -
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Brazil 1931 only - Oct 3 11:00 1:00 D
-Rule Brazil 1932 1933 - Apr 1 0:00 0 S
-Rule Brazil 1932 only - Oct 3 0:00 1:00 D
-Rule Brazil 1949 1952 - Dec 1 0:00 1:00 D
-Rule Brazil 1950 only - Apr 16 0:00 0 S
-Rule Brazil 1951 1953 - Apr 1 0:00 0 S
-Rule Brazil 1963 only - Dec 9 0:00 1:00 D
-Rule Brazil 1964 only - Mar 1 0:00 0 S
-Rule Brazil 1965 only - Jan 31 0:00 1:00 D
-Rule Brazil 1965 only - Apr 1 0:00 0 S
-Rule Brazil 1965 only - Dec 1 0:00 1:00 D
-Rule Brazil 1966 1968 - Mar 1 0:00 0 S
-Rule Brazil 1966 1967 - Nov 1 0:00 1:00 D
-Rule Brazil 1985 only - Nov 2 0:00 1:00 D
-Rule Brazil 1986 only - Mar 15 0:00 0 S
-Rule Brazil 1986 1987 - Oct Sat<=28 0:00 1:00 D
-Rule Brazil 1987 only - Feb 14 0:00 0 S
-Rule Brazil 1988 only - Feb 7 0:00 0 S
-Rule Brazil 1989 only - Jan 22 0:00 0 S
-Rule Brazil 1988 1989 - Oct Sun>=10 0:00 1:00 D
-Rule Brazil 1990 1991 - Feb Sun>=11 0:00 0 S
-Rule Brazil 1990 1992 - Oct Sun>=20 0:00 1:00 D
-Rule Brazil 1992 only - Feb 9 0:00 0 S
-Rule Brazil 1993 max - Oct Sun>=11 0:00 1:00 D
-Rule Brazil 1993 only - Jan 31 0:00 0 S
-Rule Brazil 1994 1995 - Feb Sun>=15 0:00 0 S
-Rule Brazil 1996 max - Feb Sun>=11 0:00 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
#
-# Fernando de Noronha
+# Atlantic islands: Fernando de Noronha, Trindade, Martin Vaz,
+# Atol das Rocas, and Penedos de Sao Pedro e Sao Paulo
Zone America/Noronha -2:09:40 - LMT 1914
- -2:00 - FST 1963 Dec 9
- -2:00 Brazil F%sT 1990 Jul
- -2:00 - FST
+ -2:00 Brazil FN%sT 1990 Sep 17
+ -2:00 - FNT
#
-# Amapa, east Para, Maranhao, Piaui, Ceara, Rio Grande do Norte, Paraiba,
-# Pernambuco (except Fernando de Noronha)
+# Amapa (AP), east Para (PA)
+# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
+Zone America/Belem -3:13:56 - LMT 1914
+ -3:00 Brazil BR%sT 1988 Sep 12
+ -3:00 - BRT
+#
+# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
+# Paraiba (PB)
Zone America/Fortaleza -2:34:00 - LMT 1914
- -3:00 - EST 1963 Dec 9
- -3:00 Brazil E%sT 1990 Jul
- -3:00 - EST
+ -3:00 Brazil BR%sT 1990 Sep 17
+ -3:00 - BRT 1999 Sep 30
+ -3:00 Brazil BR%sT 2000 Oct 22
+ -3:00 - BRT
+#
+# Pernambuco (PE) (except Atlantic islands)
+Zone America/Recife -2:19:36 - LMT 1914
+ -3:00 Brazil BR%sT 1990 Sep 17
+ -3:00 - BRT 1999 Sep 30
+ -3:00 Brazil BR%sT 2000 Oct 15
+ -3:00 - BRT
#
-# Alagoas, Sergipe, Tocantins
+# Tocantins (TO)
+Zone America/Araguaina -3:12:48 - LMT 1914
+ -3:00 Brazil BR%sT 1990 Sep 17
+ -3:00 - BRT 1995 Sep 14
+ -3:00 Brazil BR%sT
+#
+# Alagoas (AL), Sergipe (SE)
Zone America/Maceio -2:22:52 - LMT 1914
- -3:00 - EST 1963 Dec 9
- -3:00 Brazil E%sT 1990 Jul
- -3:00 - EST 1995 Jul
- -3:00 Brazil E%sT
+ -3:00 Brazil BR%sT 1990 Sep 17
+ -3:00 - BRT 1995 Oct 13
+ -3:00 Brazil BR%sT 1996 Sep 4
+ -3:00 - BRT 1999 Sep 30
+ -3:00 Brazil BR%sT 2000 Oct 22
+ -3:00 - BRT
#
-# Bahia, Goias, Distrito Federal, Minas Gerais, Espirito Santo, Rio de Janeiro,
-# Sao Paulo, Parana, Santa Catarina, Rio Grande do Sul
+# Bahia (BA), Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
+# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
+# Santa Catarina (SC), Rio Grande do Sul (RS)
Zone America/Sao_Paulo -3:06:28 - LMT 1914
- -3:00 Brazil E%sT
+ -3:00 Brazil BR%sT 1963 Oct 23 00:00
+ -3:00 1:00 BRST 1964
+ -3:00 Brazil BR%sT
#
# Mato Grosso, Mato Grosso do Sul
Zone America/Cuiaba -3:44:20 - LMT 1914
- -4:00 - WST 1963 Dec 9
- -4:00 Brazil W%sT
+ -4:00 Brazil AM%sT
+#
+# west Para (PA), Rondonia (RO)
+# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
+Zone America/Porto_Velho -4:15:36 - LMT 1914
+ -4:00 Brazil AM%sT 1988 Sep 12
+ -4:00 - AMT
+#
+# Roraima (RR)
+Zone America/Boa_Vista -4:02:40 - LMT 1914
+ -4:00 Brazil AM%sT 1988 Sep 12
+ -4:00 - AMT 1999 Sep 30
+ -4:00 Brazil AM%sT 2000 Oct 15
+ -4:00 - AMT
#
-# Roraima, west Para, Amazonas, Rondonia
+# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
Zone America/Manaus -4:00:04 - LMT 1914
- -4:00 - WST 1963 Dec 9
- -4:00 Brazil W%sT 1990 Jul
- -4:00 - WST
+ -4:00 Brazil AM%sT 1988 Sep 12
+ -4:00 - AMT 1993 Sep 28
+ -4:00 Brazil AM%sT 1994 Sep 22
+ -4:00 - AMT
#
-# Acre
-# Rio_Branco is too ambiguous, since there's a Rio Branco in Uruguay too.
-Zone America/Porto_Acre -4:31:12 - LMT 1914
- -5:00 - AST 1963 Dec 9
- -5:00 Brazil A%sT 1988 Jul
- -5:00 - AST
+# west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
+# Eirunepe, Envira, Ipixuna
+Zone America/Eirunepe -4:39:28 - LMT 1914
+ -5:00 Brazil AC%sT 1988 Sep 12
+ -5:00 - ACT 1993 Sep 28
+ -5:00 Brazil AC%sT 1994 Sep 22
+ -5:00 - ACT
#
-# Martin Vaz and Trinidade are like America/Noronha.
+# Acre (AC)
+Zone America/Rio_Branco -4:31:12 - LMT 1914
+ -5:00 Brazil AC%sT 1988 Sep 12
+ -5:00 - ACT
# Chile
# From Eduardo Krell (1995-10-19):
# The law says to switch to DST at midnight [24:00] on the second SATURDAY
# of October.... The law is the same for March and October.
+# (1998-09-29):
+# Because of the drought this year, the government decided to go into
+# DST earlier (saturday 9/26 at 24:00). This is a one-time change only ...
+# (unless there's another dry season next year, I guess).
+
+# From Julio I. Pacheco Troncoso (1999-03-18):
+# Because of the same drought, the government decided to end DST later,
+# on April 3, (one-time change).
+
+# From Gwillim Law (2001-02-20):
+# I came across a Chilean on-line newspaper, La Tercera. Its
+# <a href="http://www.tercera.cl/diario/1998/03/13/extras.html">
+# 1998-03-13 issue
+# </a>, says (my translation):
+# "At 24:00 (midnight) tomorrow (Saturday) - 22:00 in the insular
+# territory [Easter Island, Juan Fernandez, etc.] - winter time will
+# begin in the entire country."
+
+# From Paul Eggert (2001-02-21):
+# Assume this rule has been used since DST was introduced in the islands.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Chile 1918 only - Sep 1 0:00 1:00 S
-Rule Chile 1919 only - Jul 2 0:00 0 -
-Rule Chile 1927 1931 - Sep 1 0:00 1:00 S
-Rule Chile 1928 1932 - Apr 1 0:00 0 -
-Rule Chile 1969 max - Oct Sun>=9 0:00 1:00 S
-Rule Chile 1970 max - Mar Sun>=9 0:00 0 -
+Rule Chile 1918 only - Sep 1 0:00 1:00 S
+Rule Chile 1919 only - Jul 2 0:00 0 -
+Rule Chile 1927 1931 - Sep 1 0:00 1:00 S
+Rule Chile 1928 1932 - Apr 1 0:00 0 -
+Rule Chile 1969 1997 - Oct Sun>=9 4:00u 1:00 S
+Rule Chile 1970 1998 - Mar Sun>=9 3:00u 0 -
+Rule Chile 1998 only - Sep 27 4:00u 1:00 S
+Rule Chile 1999 only - Apr 4 3:00u 0 -
+Rule Chile 1999 max - Oct Sun>=9 4:00u 1:00 S
+Rule Chile 2000 max - Mar Sun>=9 3:00u 0 -
# IATA SSIM anomalies: (1990-09) says 1990-09-16; (1992-02) says 1992-03-14;
-# (1996-09) says 1998-03-08. Ignore these for now.
+# (1996-09) says 1998-03-08. Ignore these.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Santiago -4:42:40 - LMT 1890
-4:42:40 - SMT 1910 # Santiago Mean Time
# Colombia
+# Shanks specifies 24:00 for 1992 transition times; go with IATA,
+# as it seems implausible to change clocks at midnight New Year's Eve.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule CO 1992 only - May 2 0:00 1:00 S
Rule CO 1992 only - Dec 31 0:00 0 -
# no information; probably like America/Bogota
# Curacao
+# Shanks says that Bottom and Oranjestad have been at -4:00 since
+# standard time was introduced on 1912-03-02; and that Kralendijk and Rincon
+# used Kralendijk Mean Time (-4:33:08) from 1912-02-02 to 1965-01-01.
+# This all predates our 1970 cutoff, though.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Curacao -4:35:44 - LMT 1912 Feb 12 # Willemstad
-4:30 - ANT 1965 # Netherlands Antilles Time
-6:00 - GALT # Galapagos Time
# Falklands
+
+# From Paul Eggert (2001-03-05):
+# Between 1990 and 2000 inclusive, Shanks and the IATA agree except
+# the IATA gives 1996-09-08. Go with Shanks.
+
+# From Falkland Islands Government Office, London (2001-01-22)
+# via Jesper Norgaard:
+# ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
+# April 2001 and advance one hour to summer time at 2 am on Sunday 2
+# September. It is anticipated that the clocks will revert back at 2
+# am on Sunday 21 April 2002 and advance to summer time at 2 am on
+# Sunday 1 September.
+
+# From Rives McDow (2001-02-13):
+#
+# I have communicated several times with people there, and the last
+# time I had communications that was helpful was in 1998. Here is
+# what was said then:
+#
+# "The general rule was that Stanley used daylight saving and the Camp
+# did not. However for various reasons many people in the Camp have
+# started to use daylight saving (known locally as 'Stanley Time')
+# There is no rule as to who uses daylight saving - it is a matter of
+# personal choice and so it is impossible to draw a map showing who
+# uses it and who does not. Any list would be out of date as soon as
+# it was produced. This year daylight saving ended on April 18/19th
+# and started again on September 12/13th. I do not know what the rule
+# is, but can find out if you like. We do not change at the same time
+# as UK or Chile."
+#
+# I did have in my notes that the rule was "Second Saturday in Sep at
+# 0:00 until third Saturday in Apr at 0:00". I think that this does
+# not agree in some cases with Shanks; is this true?
+#
+# Also, there is no mention in the list that some areas in the
+# Falklands do not use DST. I have found in my communications there
+# that these areas are on the western half of East Falkland and all of
+# West Falkland. Stanley is the only place that consistently observes
+# DST. Again, as in other places in the world, the farmers don't like
+# it. West Falkland is almost entirely sheep farmers.
+#
+# I know one lady there that keeps a list of which farm keeps DST and
+# which doesn't each year. She runs a shop in Stanley, and says that
+# the list changes each year. She uses it to communicate to her
+# customers, catching them when they are home for lunch or dinner.
+
+# From Paul Eggert (2001-03-05):
+# For now, we'll just record the time in Stanley, since we have no
+# better info.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Falk 1937 1938 - Sep lastSun 0:00 1:00 S
Rule Falk 1938 1942 - Mar Sun>=19 0:00 0 -
Rule Falk 1983 only - Sep lastSun 0:00 1:00 S
Rule Falk 1984 1985 - Apr lastSun 0:00 0 -
Rule Falk 1984 only - Sep 16 0:00 1:00 S
-Rule Falk 1985 1995 - Sep Sun>=9 0:00 1:00 S
-Rule Falk 1986 max - Apr Sun>=16 0:00 0 -
-Rule Falk 1996 max - Sep Sun>=8 0:00 1:00 S
+Rule Falk 1985 2000 - Sep Sun>=9 0:00 1:00 S
+Rule Falk 1986 2000 - Apr Sun>=16 0:00 0 -
+Rule Falk 2001 max - Apr Sun>=15 2:00 0 -
+Rule Falk 2001 max - Sep Sun>=1 2:00 1:00 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Atlantic/Stanley -3:51:24 - LMT 1890
-3:51:24 - SMT 1912 Mar 12 # Stanley Mean Time
-4:00 - GYT
# Paraguay
-
-# From Bob Devine (1988-01-28):
-# Paraguay: First day in October to last in March. Midnight switch??
-# Since 1980.
-
-# From U. S. Naval Observatory (1989-01-19):
-# PARAGUAY 4 H BEHIND UTC
-# PARAGUAY 3 H BEHIND UTC OCT 1, '88-MAR 31, '89
-
-# From Shanks (1991):
+# From Paul Eggert (1999-10-29):
+# Shanks (1999) says that spring transitions are from 01:00 -> 02:00,
+# and autumn transitions are from 00:00 -> 23:00. Go with earlier
+# editions of Shanks, and with the IATA, who say transitions occur at 00:00.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Para 1975 1978 - Oct 1 0:00 1:00 S
+Rule Para 1975 1988 - Oct 1 0:00 1:00 S
Rule Para 1975 1978 - Mar 1 0:00 0 -
-# Shanks says 1979 was all DST.
-Rule Para 1980 1991 - Apr 1 0:00 0 -
-Rule Para 1980 1988 - Oct 1 0:00 1:00 S
+Rule Para 1979 1991 - Apr 1 0:00 0 -
Rule Para 1989 only - Oct 22 0:00 1:00 S
Rule Para 1990 only - Oct 1 0:00 1:00 S
Rule Para 1991 only - Oct 6 0:00 1:00 S
Rule Para 1992 only - Mar 1 0:00 0 -
Rule Para 1992 only - Oct 5 0:00 1:00 S
Rule Para 1993 only - Mar 31 0:00 0 -
-Rule Para 1993 max - Oct 1 0:00 1:00 S
+Rule Para 1993 1995 - Oct 1 0:00 1:00 S
Rule Para 1994 1995 - Feb lastSun 0:00 0 -
-Rule Para 1996 max - Mar 1 0:00 0 -
+Rule Para 1996 only - Mar 1 0:00 0 -
+# IATA SSIM (2000-02) says 1999-10-10; ignore this for now.
+# From Steffen Thorsen (2000-10-02):
+# I have three independent reports that Paraguay changed to DST this Sunday
+# (10-01).
+#
+# Translated by Gwillim Law (2001-02-27) from
+# <a href="http://www.diarionoticias.com.py/011000/nacional/naciona1.htm">
+# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
+# </a>:
+# Starting at 0:00 today, the clock will be set forward 60 minutes, in
+# fulfillment of Decree No. 7,273 of the Executive Power.... The time change
+# system has been operating for several years. Formerly there was a separate
+# decree each year; the new law has the same effect, but permanently. Every
+# year, the time will change on the first Sunday of October; likewise, the
+# clock will be set back on the first Sunday of March.
+#
+# From Jesper Norgaard (2001-03-06) [an official URL saying similar things]:
+# http://gateway.abc.com.py:8000/pub/pag04.mbr/artic?FHA=2001-03-03-02.24.52.900592
+#
+Rule Para 1996 max - Oct Sun>=1 0:00 1:00 S
+# IATA SSIM (1997-09) says Mar 1; go with Shanks.
+Rule Para 1997 only - Feb lastSun 0:00 0 -
+# Shanks says 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
+# (1999-09) reports no date; go with above sources and Gerd Knops (2001-02-27).
+Rule Para 1998 max - Mar Sun>=1 0:00 0 -
+
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Asuncion -3:50:40 - LMT 1890
-3:50:40 - AMT 1931 Oct 10 # Asuncion Mean Time
Rule Peru 1987 only - Apr 1 0:00 0 -
Rule Peru 1990 only - Jan 1 0:00 1:00 S
Rule Peru 1990 only - Apr 1 0:00 0 -
-Rule Peru 1993 only - Jan 1 0:00 1:00 S
-Rule Peru 1993 only - Apr 1 0:00 0 -
+# IATA is ambiguous for 1993/1995; go with Shanks.
+Rule Peru 1994 only - Jan 1 0:00 1:00 S
+Rule Peru 1994 only - Apr 1 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Lima -5:08:12 - LMT 1890
-5:09 - LMT 1908 Jul 28 # Lima Mean Time
-2:00 - GST # South Georgia Time
# South Sandwich Is
-# uninhabited
+# uninhabited; scientific personnel have wintered
# Suriname
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
# Uruguay
# From Paul Eggert <eggert@twinsun.com> (1993-11-18):
# Uruguay wins the prize for the strangest peacetime manipulation of the rules.
-# From Shanks (1991):
+# From Shanks:
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
# Whitman gives 1923 Oct 1; go with Shanks.
Rule Uruguay 1923 only - Oct 2 0:00 0:30 HS
Rule Uruguay 1988 only - Dec 11 0:00 1:00 S
Rule Uruguay 1989 only - Mar 12 0:00 0 -
Rule Uruguay 1989 only - Oct 29 0:00 1:00 S
+# Shanks says no DST was observed in 1990/1 and 1991/2,
+# and that 1992/3's DST was from 10-25 to 03-01. Go with IATA.
Rule Uruguay 1990 1992 - Mar Sun>=1 0:00 0 -
Rule Uruguay 1990 1991 - Oct Sun>=21 0:00 1:00 S
-Rule Uruguay 1992 1993 - Oct Sun>=15 0:00 1:00 S
+Rule Uruguay 1992 only - Oct 18 0:00 1:00 S
Rule Uruguay 1993 only - Feb 28 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Montevideo -3:44:44 - LMT 1898 Jun 28
-# $OpenBSD: systemv,v 1.2 1997/01/14 04:36:58 millert Exp $
-# @(#)systemv 7.2
+# @(#)systemv 7.3
# Old rules, should the need arise.
# No attempt is made to handle Newfoundland, since it cannot be expressed
# using the System V "TZ" scheme (half-hour offset), or anything outside
# North America (no support for non-standard DST start/end dates), nor
-# the change in the DST rules in the US in 1987 (can't split between
-# Canada, with no changes, and the US)
+# the change in the DST rules in the US in 1987 (which occurred before
+# the old rules were written).
#
-# Be sure to compile this *without* leap second correction for true conformance.
+# If you need the old rules, uncomment ## lines and comment-out Link lines.
+# Compile this *without* leap second correction for true conformance.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D
-Rule SystemV min 1973 - Oct lastSun 2:00 0 S
-Rule SystemV 1974 only - Jan 6 2:00 1:00 D
-Rule SystemV 1974 only - Nov lastSun 2:00 0 S
-Rule SystemV 1975 only - Feb 23 2:00 1:00 D
-Rule SystemV 1975 only - Oct lastSun 2:00 0 S
-Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D
-Rule SystemV 1976 max - Oct lastSun 2:00 0 S
+## Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D
+## Rule SystemV min 1973 - Oct lastSun 2:00 0 S
+## Rule SystemV 1974 only - Jan 6 2:00 1:00 D
+## Rule SystemV 1974 only - Nov lastSun 2:00 0 S
+## Rule SystemV 1975 only - Feb 23 2:00 1:00 D
+## Rule SystemV 1975 only - Oct lastSun 2:00 0 S
+## Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D
+## Rule SystemV 1976 max - Oct lastSun 2:00 0 S
# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]
-Zone SystemV/AST4ADT -4:00 SystemV A%sT
-Zone SystemV/EST5EDT -5:00 SystemV E%sT
-Zone SystemV/CST6CDT -6:00 SystemV C%sT
-Zone SystemV/MST7MDT -7:00 SystemV M%sT
-Zone SystemV/PST8PDT -8:00 SystemV P%sT
-Zone SystemV/YST9YDT -9:00 SystemV Y%sT
-Zone SystemV/AST4 -4:00 - AST
-Zone SystemV/EST5 -5:00 - EST
-Zone SystemV/CST6 -6:00 - CST
-Zone SystemV/MST7 -7:00 - MST
-Zone SystemV/PST8 -8:00 - PST
-Zone SystemV/YST9 -9:00 - YST
-Zone SystemV/HST10 -10:00 - HST
+## Zone SystemV/AST4ADT -4:00 SystemV A%sT
+## Zone SystemV/EST5EDT -5:00 SystemV E%sT
+## Zone SystemV/CST6CDT -6:00 SystemV C%sT
+## Zone SystemV/MST7MDT -7:00 SystemV M%sT
+## Zone SystemV/PST8PDT -8:00 SystemV P%sT
+## Zone SystemV/YST9YDT -9:00 SystemV Y%sT
+## Zone SystemV/AST4 -4:00 - AST
+## Zone SystemV/EST5 -5:00 - EST
+## Zone SystemV/CST6 -6:00 - CST
+## Zone SystemV/MST7 -7:00 - MST
+## Zone SystemV/PST8 -8:00 - PST
+## Zone SystemV/YST9 -9:00 - YST
+## Zone SystemV/HST10 -10:00 - HST
+# For now...
+Link America/Halifax SystemV/AST4ADT
+Link America/New_York SystemV/EST5EDT
+Link America/Chicago SystemV/CST6CDT
+Link America/Denver SystemV/MST7MDT
+Link America/Los_Angeles SystemV/PST8PDT
+Link America/Anchorage SystemV/YST9YDT
+Link America/Puerto_Rico SystemV/AST4
+Link America/Indianapolis SystemV/EST5
+Link America/Regina SystemV/CST6
+Link America/Phoenix SystemV/MST7
+Link Pacific/Pitcairn SystemV/PST8
+Link Pacific/Gambier SystemV/YST9
+Link Pacific/Honolulu SystemV/HST10