]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.0pre4 2.2.0pre4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:56 +0000 (15:17 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:56 +0000 (15:17 -0500)
Ok, you know the drill by now. This fixes:
 - yes, people told me about the new and improved ksymoops. Much better,
   no need for C++, and this one actually seems to compile and work
   reliably.
 - ntfs fixes
 - the vfat thing _really_ works now
 - NFS fix for deleting files while writebacks active.
 - ppa/imm driver updated
 - minor mm balancing patches
 - Alan took the gauntlet and cleaned up some CONFIG_PROC_FS stuff.
More on Monday,

                Linus

84 files changed:
Documentation/Configure.help
Documentation/oops-tracing.txt
Makefile
README
arch/i386/boot/Makefile
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
drivers/char/misc.c
drivers/char/tty_io.c
drivers/misc/parport_arc.c
drivers/misc/parport_ax.c
drivers/misc/parport_init.c
drivers/misc/parport_pc.c
drivers/misc/parport_procfs.c
drivers/net/ibmtr.c
drivers/pci/oldproc.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/aic7xxx.c
drivers/scsi/eata_dma_proc.c
drivers/scsi/eata_pio_proc.c
drivers/scsi/imm.c
drivers/scsi/imm.h
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_syms.c
drivers/sound/soundcard.c
fs/binfmt_misc.c
fs/fat/inode.c
fs/nfs/write.c
fs/nfsd/nfsctl.c
fs/nfsd/stats.c
fs/nfsd/vfs.c
fs/ntfs/Makefile
fs/ntfs/attr.c
fs/ntfs/attr.h
fs/ntfs/dir.c
fs/ntfs/dir.h
fs/ntfs/fs.c
fs/ntfs/inode.c
fs/ntfs/inode.h
fs/ntfs/macros.h
fs/ntfs/ntfsendian.h [new file with mode: 0644]
fs/ntfs/ntfstypes.h [new file with mode: 0644]
fs/ntfs/super.c
fs/ntfs/super.h
fs/ntfs/support.c
fs/ntfs/support.h
fs/ntfs/sysctl.h
fs/ntfs/types.h [deleted file]
fs/ntfs/util.c
fs/ntfs/util.h
fs/proc/procfs_syms.c
include/linux/fs.h
include/linux/pci.h
include/linux/proc_fs.h
include/linux/sunrpc/stats.h
include/linux/swapctl.h
ipc/util.c
mm/page_alloc.c
mm/vmscan.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sysctl.c
scripts/header.tk
scripts/ksymoops-0.6/Makefile [new file with mode: 0644]
scripts/ksymoops-0.6/README [new file with mode: 0644]
scripts/ksymoops-0.6/io.c [new file with mode: 0644]
scripts/ksymoops-0.6/ksymoops.c [new file with mode: 0644]
scripts/ksymoops-0.6/ksymoops.h [new file with mode: 0644]
scripts/ksymoops-0.6/ksyms.c [new file with mode: 0644]
scripts/ksymoops-0.6/map.c [new file with mode: 0644]
scripts/ksymoops-0.6/misc.c [new file with mode: 0644]
scripts/ksymoops-0.6/object.c [new file with mode: 0644]
scripts/ksymoops-0.6/oops.c [new file with mode: 0644]
scripts/ksymoops-0.6/patches/README [new file with mode: 0644]
scripts/ksymoops-0.6/patches/mips [new file with mode: 0644]
scripts/ksymoops-0.6/patches/ppc [new file with mode: 0644]
scripts/ksymoops-0.6/re.c [new file with mode: 0644]
scripts/ksymoops-0.6/symbol.c [new file with mode: 0644]
scripts/ksymoops.cc [deleted file]
scripts/tkcond.c

index e9ed96aac1b7cf0f0c86cb2d7e69e06020a6f8ba..a370ced88791b80240986fd84ed59e996c3b6334 100644 (file)
@@ -1631,9 +1631,13 @@ CONFIG_FB
   information.
 
   Say Y here and to the driver for your graphics board below if you
-  are compiling a kernel for a non-x86 architecture. If you are
-  compiling for the x86 architecture, you can say Y if you want to
-  play with it, but it is not essential.
+  are compiling a kernel for a non-x86 architecture.
+
+  If you are compiling for the x86 architecture, you can say Y if you
+  want to play with it, but it is not essential. Please note that
+  running graphical applications that directly touch the hardware (e.g.
+  and accelerated X server) and that are not frame buffer device-aware
+  may cause unexpected results. If unsure, say N.
 
 Acorn VIDC support
 CONFIG_FB_ACORN
@@ -4356,23 +4360,44 @@ CONFIG_SCSI_PPA
   drive: it will be supported automatically if you said Y to the
   generic "SCSI disk support", above.
 
+  The ZIP Plus drive is supported by the imm driver, also more recent
+  parallel port ZIP drives use an imm compatible interface. If the
+  supplied cable with the drive is labeled "AutoDetect" then you will
+  need the imm driver.
+
   This driver is also available as a module which can be inserted in
   and removed from the running kernel whenever you want. To compile
   this driver as a module, say M here and read
   Documentation/modules.txt. The module will be called ppa.o. 
 
-EPP FIFO Checking
-CONFIG_SCSI_PPA_HAVE_PEDANTIC
+IOMEGA Parallel Port ZIP drive SCSI support
+CONFIG_SCSI_IMM
+  All "new and improved" parallel port to SCSI interface from Iomega.
+  Please read the comments for the ppa driver for further information
+
+Force the Iomega ZIP drivers to use EPP-16
+CONFIG_SCSI_IZIP_EPP16
   EPP (Enhanced Parallel Port) is a standard for parallel ports which
   allows them to act as expansion buses that can handle up to 64
-  peripheral devices. Some parallel port chipsets are slower than
-  their motherboard, and so we have to control the state of the
-  chipset's FIFO queue every now and then to avoid data loss. This
-  will be done if you say Y here. 
+  peripheral devices.
+
+  Some parallel port chipsets are slower than their motherboard, and
+  so we have to control the state of the chipset's FIFO queue every
+  now and then to avoid data loss. This will be done if you say Y here. 
   
-  If your EPP chipset is from the SMC series, you are likely to have
-  to say Y here. Generally, saying Y is the safe option and slows
-  things down a bit.
+  Generally, saying Y is the safe option and slows things down a bit.
+
+Assume slow parallel port control register
+CONFIG_SCSI_IZIP_SLOW_CTR
+  Some parallel ports are known to have excessive delays between changing
+  the parallel port control register and good data being available on
+  the parallel port data/status register. This option forces a small delay
+  (1.0 usec to be exact) after changing the control register to let things
+  settle out. Enabling this option may result in a big drop in performance
+  but some very old parallel ports (found in 386 vintage machines) will
+  not work properly.
+
+  Generally, saying N is fine.
 
 SCSI Debug host simulator.
 CONFIG_SCSI_DEBUG
index 6e685aa642203b7045c695438c18e48450338e4c..349d1a05f4d979c101a6685bb14d963faebb3fe3 100644 (file)
@@ -1,3 +1,24 @@
+Quick Summary
+-------------
+
+cd /usr/src/linux/scripts
+g++ -o ksymoops ksymoops.cc
+./ksymoops ../System.map < the_oops.txt
+
+and send the output the maintainer of the kernel area that seems to be
+involved with the problem. Don't worry too much about getting the wrong
+person. If you are unsure send it to the person responsible for the code
+relevant to what you were doing. If it occurs repeatably try and describe
+how to recreate it. Thats worth even more than the oops
+
+If you are totally stumped as to whom to send the report, send it to 
+linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as
+stable as humanly possible.
+
+
+Full Information
+----------------
+
 From: Linus Torvalds <torvalds@cs.helsinki.fi>
 
 How to track down an Oops.. [originally a mail to linux-kernel]
index 4678543b980c8d94cab2c76efff60637cb8fc69f..72c662c7e4840b3fdabce69be224baf45a1f2c63 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff --git a/README b/README
index 2ae083d4b847ae3ae9474a11f8b3ca0d6f52ec69..11a3016678fe72044bb99f58375252f124542837 100644 (file)
--- a/README
+++ b/README
@@ -1,23 +1,9 @@
-       Linux kernel release 2.1.xx
+       Linux kernel release 2.2.xx
 
-These are the release notes for Linux version 2.1.  Read them carefully,
+These are the release notes for Linux version 2.2.  Read them carefully,
 as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong. 
 
-Linux version 2.1 is a DEVELOPMENT kernel, and not intended for general
-public use.  Different releases may have various and sometimes severe
-bugs.  It is *strongly* recommended that you back up the previous kernel
-before installing any new 2.1.xx release.
-
-If you need to use a proven and stable Linux kernel, please use 1.0.9,
-1.2.13, or 2.0.xx.  All features which will be in the 2.1.xx releases will
-be contained in 2.2.xx when the code base has stabilized again.
-
-If you decide to use 2.1, it is recommended that you join the kernel mailing
-list.  To do this, e-mail majordomo@vger.rutgers.edu, and put in the body
-of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest"
-for a daily digest of the mailing list (it is a high-traffic list.)
-
 However, please make sure you don't ask questions which are already answered
 in various files in the Documentation directory.  See DOCUMENTATION below.
 
index ff26d087c4c5dd4264d08ff1cd08828cb52f566b..64b9377a268897d1d83d84880ba1af710cb40098 100644 (file)
@@ -40,7 +40,7 @@ zlilo: $(CONFIGURE) $(BOOTIMAGE)
        if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 install: $(CONFIGURE) $(BOOTIMAGE)
-       sh -x ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
+       sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
 tools/build: tools/build.c
        $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
index ffb1eca5fb7e89940277a30564fd732e79456452..2fd9c39eba3935fb680b11abcecd7fa601197d02 100644 (file)
@@ -675,7 +675,7 @@ int get_cpuinfo(char * buffer)
                        p += sprintf(p, "stepping\t: unknown\n");
 
                if (c->x86_capability & X86_FEATURE_TSC) {
-                       p += sprintf(p, "cpu MHz\t\t: %lu.%02lu\n",
+                       p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
                                cpu_hz / 1000000, (cpu_hz % 1000000));
                }
 
@@ -689,6 +689,8 @@ int get_cpuinfo(char * buffer)
                } else if (c->x86_vendor == X86_VENDOR_AMD) {
                        x86_cap_flags[16] = "fcmov";
                        x86_cap_flags[31] = "3dnow";
+                       if (c->x86 == 5 && c->x86_model == 6)
+                               x86_cap_flags[10] = "sep";
                } else if (c->x86_vendor == X86_VENDOR_INTEL) {
                        x86_cap_flags[6] = "pae";
                        x86_cap_flags[9] = "apic";
index 986313edda771c26875d957571a99cef57ec8fe7..7c48420e8894e99124be90e04937b8353a44fb09 100644 (file)
@@ -1126,6 +1126,7 @@ void __init smp_boot_cpus(void)
        {
                printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
                io_apic_irqs = 0;
+               cpu_online_map = cpu_present_map;
                goto smp_done;
        }
 
index dcc53bd643dccfd693c5f30e4342a544cff30958..96907ef57d12e5caeb1c1c3433e7057e3d672ae6 100644 (file)
@@ -86,7 +86,6 @@ extern void hfmodem_init(void);
 extern int pc110pad_init(void);
 extern int pmu_device_init(void);
 
-#ifdef CONFIG_PROC_FS
 static int misc_read_proc(char *buf, char **start, off_t offset,
                          int len, int *eof, void *private)
 {
@@ -99,7 +98,6 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
        return len > offset ? len - offset : 0;
 }
 
-#endif /* PROC_FS */
 
 static int misc_open(struct inode * inode, struct file * file)
 {
@@ -185,17 +183,13 @@ int misc_deregister(struct miscdevice * misc)
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
-#if defined(CONFIG_PROC_FS)
 static struct proc_dir_entry *proc_misc;       
-#endif
 
 int __init misc_init(void)
 {
-#ifdef CONFIG_PROC_FS
        proc_misc = create_proc_entry("misc", 0, 0);
        if (proc_misc)
                proc_misc->read_proc = misc_read_proc;
-#endif /* PROC_FS */
 #ifdef CONFIG_BUSMOUSE
        bus_mouse_init();
 #endif
index ee2e7e099a2765acf9a6aedc8e96193860925bd0..007dd9048907b28599f9207f36070f017932e083 100644 (file)
@@ -77,9 +77,7 @@
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/poll.h>
-#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-#endif
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 
@@ -1966,9 +1964,7 @@ int tty_register_driver(struct tty_driver *driver)
        if (tty_drivers) tty_drivers->prev = driver;
        tty_drivers = driver;
        
-#ifdef CONFIG_PROC_FS
        proc_tty_register_driver(driver);
-#endif 
        return error;
 }
 
@@ -2010,9 +2006,7 @@ int tty_unregister_driver(struct tty_driver *driver)
        if (driver->next)
                driver->next->prev = driver->prev;
 
-#ifdef CONFIG_PROC_FS
        proc_tty_unregister_driver(driver);
-#endif
        return 0;
 }
 
index 134bec7d7f350eba9c43c175765295f61dc2fa20..f9c4ee46bb890a9d8591ae1b9afa4aa35e58a550 100644 (file)
@@ -142,9 +142,7 @@ int parport_arc_init(void)
 
        printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
               p->irq);
-#ifdef CONFIG_PROC_FS
        parport_proc_register(p);
-#endif
        p->flags |= PARPORT_FLAG_COMA;
 
        if (parport_probe_hook)
index 4638845331c717b0a98b69fa869dde052c16bf68..d7697eff2759287582e7438a08b9c624887840e8 100644 (file)
@@ -586,9 +586,7 @@ init_one_port(struct linux_ebus_device *dev)
                printmode(ECPPS2);
        }
        printk("]\n");
-#ifdef CONFIG_PROC_FS
        parport_proc_register(p);
-#endif
        p->flags |= PARPORT_FLAG_COMA;
 
        p->ops->write_control(p, 0x0c);
@@ -631,9 +629,7 @@ cleanup_module(void)
                if (p->modes & PARPORT_MODE_PCSPP) { 
                        if (!(p->flags & PARPORT_FLAG_COMA)) 
                                parport_quiesce(p);
-#ifdef CONFIG_PROC_FS
                        parport_proc_unregister(p);
-#endif
                        parport_unregister_port(p);
                }
                p = tmp;
index 7fcefe436d690476b6f2332982598a6e4d2a5875..473c1b224683a86565208e9d686529d6e1dd4680 100644 (file)
@@ -98,19 +98,17 @@ __initfunc(void parport_setup(char *str, int *ints))
 #ifdef MODULE
 int init_module(void)
 {
-#ifdef CONFIG_PROC_FS
        (void)parport_proc_init();      /* We can go on without it. */
-#endif
        return 0;
 }
 
 void cleanup_module(void)
 {
-#ifdef CONFIG_PROC_FS
        parport_proc_cleanup();
-#endif
 }
+
 #else
+
 __initfunc(int parport_init(void))
 {
        if (io[0] == PARPORT_DISABLE) 
@@ -145,10 +143,8 @@ EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
 EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
 EXPORT_SYMBOL(parport_wait_peripheral);
-#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
-#endif
 EXPORT_SYMBOL(parport_probe_hook);
 EXPORT_SYMBOL(parport_parse_irqs);
 
index cddb1dffe15cc714bdc6e06409ace31435420e91..b51dbe1bd4f6b984d842d99da1213d711912d7be 100644 (file)
@@ -759,8 +759,8 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
 #ifdef CONFIG_PROC_FS
        if (probedirq != PARPORT_IRQ_NONE) 
                printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
-       parport_proc_register(p);
 #endif
+       parport_proc_register(p);
        p->flags |= PARPORT_FLAG_COMA;
 
        /* Done probing.  Now put the port into a sensible start-up state. */
@@ -824,9 +824,7 @@ void cleanup_module(void)
                if (p->modes & PARPORT_MODE_PCSPP) { 
                        if (!(p->flags & PARPORT_FLAG_COMA)) 
                                parport_quiesce(p);
-#ifdef CONFIG_PROC_FS
                        parport_proc_unregister(p);
-#endif
                        parport_unregister_port(p);
                }
                p = tmp;
index dd92e895728a8cc34b6139438297d099e3dd8535..4acc2c542922e8669e9c5e9c5807ca18305086de 100644 (file)
@@ -27,6 +27,8 @@
 #include <asm/dma.h>
 #include <asm/irq.h>
 
+#ifdef CONFIG_PROC_FS
+
 struct proc_dir_entry *base = NULL;
 
 static int irq_write_proc(struct file *file, const char *buffer,
@@ -305,12 +307,11 @@ int parport_proc_init(void)
 {
        base = new_proc_entry("parport", S_IFDIR, &proc_root,PROC_PARPORT,
                              NULL);
-       base->fill_inode = &parport_modcount;
-
        if (base == NULL) {
                printk(KERN_ERR "Unable to initialise /proc/parport.\n");
                return 0;
        }
+       base->fill_inode = &parport_modcount;
 
        return 1;
 }
@@ -385,3 +386,26 @@ int parport_proc_unregister(struct parport *pp)
        destroy_proc_tree(pp);
        return 0;
 }
+
+#else
+
+int parport_proc_register(struct parport *p) 
+{
+       return 0;
+}
+
+int parport_proc_unregister(struct parport *p)
+{
+       return 0;
+}
+
+int parport_proc_init(void)
+{
+       return 0;
+}
+
+void parport_proc_cleanup(void)
+{
+}
+
+#endif
index cf318f92704b461d816ea6e60c84a4702b39d86a..6290ac88261a5f0d389131db11762a9adff4a213 100644 (file)
  *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
  *        May 25 1998)
  *      + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998)
+ *
+ *      Changes by Joel Sloan (jjs@c-me.com) :
+ *      + disable verbose debug messages by default - to enable verbose
+ *       debugging, edit the IBMTR_DEBUG_MESSAGES define below 
  */
 
+/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
+in the event that chatty debug messages are desired - jjs 12/30/98 */
+
+#define IBMTR_DEBUG_MESSAGES 0
+
 #ifdef PCMCIA
 #define MODULE
 #endif
 /* version and credits */
 static char *version =
 "ibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-"         v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n";
+"         v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"
+"         v2.2.0   12/30/98 Joel Sloan <jjs@c-me.com>\n";
 
 static char pcchannelid[] = {
        0x05, 0x00, 0x04, 0x09,
@@ -999,6 +1009,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                                                DPRINTK("error on dir_read_log: %02X\n",
                                                        (int)readb(ti->srb+offsetof(struct srb_read_log, ret_code)));
                                        else
+                                           if (IBMTR_DEBUG_MESSAGES) {
                                                DPRINTK(
                                                        "Line errors %02X, Internal errors %02X, Burst errors %02X\n"
                                                        "A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n"
@@ -1023,6 +1034,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                                                                                    frequency_errors)),
                                                        (int)readb(ti->srb+offsetof(struct srb_read_log,
                                                                                                    token_errors)));
+                                           }
                                        dev->tbusy=0;
                                        break;
 
index afbb68c75953a3e533d3f8007afcbf318c852749..bfaef7b7e96b61b7eddad105b0e52cc0e068260f 100644 (file)
@@ -541,6 +541,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( ADAPTEC2,       ADAPTEC2_2940U2,"AHA-2940U2"),
        DEVICE( ADAPTEC2,       ADAPTEC2_7890,  "AIC-7890/1"),
        DEVICE( ADAPTEC2,       ADAPTEC2_3940U2,"AHA-3940U2"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_3950U2D,"AHA-3950U2D"),
        DEVICE( ADAPTEC2,       ADAPTEC2_7896,  "AIC-7896/7"),
        DEVICE( ATRONICS,       ATRONICS_2015,  "IDE-2015PL"),
        DEVICE( TIGERJET,       TIGERJET_300,   "Tiger300 ISDN"),
index 30ddde6a34c45ff5620d19bb9b7e1910b78a1289..686df3085af24e495ff9d4241a52336c41b47334 100644 (file)
@@ -58,13 +58,6 @@ if [ "$CONFIG_MCA" = "y" ]; then
 fi
 dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
-  if [ "$CONFIG_SCSI_PPA" != "n" ]; then
-    bool  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC
-  fi
-  dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
-fi
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
        bool '   Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400
        choice 'NCR5380/53c400 mapping method (use Port for T130B)' \
@@ -74,6 +67,14 @@ fi
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI
 fi
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
+  dep_tristate 'IOMEGA parallel port (imm - newer drives)' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
+  if [ "$CONFIG_SCSI_PPA" != "n" -o "$CONFIG_SCSI_IMM" != "n" ]; then
+    bool  '  ppa/imm option - Use slow (but safe) EPP-16' CONFIG_SCSI_IZIP_EPP16
+    bool  '  ppa/imm option - Assume slow parport control register' CONFIG_SCSI_IZIP_SLOW_CTR
+  fi
+fi
 dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
index a27394de6901bb3198f5b3cd3f8bcb834399ac2f..cbffa8aa107dd50c8ad1e381fb33965a59d4bed4 100644 (file)
@@ -41,9 +41,7 @@ ifeq ($(CONFIG_SCSI),y)
   endif
   L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o
   L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o
-  ifeq ($(CONFIG_PROC_FS),y)
-    L_OBJS += scsi_proc.o
-  endif
+  L_OBJS += scsi_proc.o
 else
   ifeq ($(CONFIG_SCSI),m)
     MIX_OBJS += scsi_syms.o
index 7dfa6ef35105790b038dc42e435bc7eb5061715c..8418ea23b5aea1c341b56ba30724697a21cb410c 100644 (file)
@@ -354,7 +354,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.6"
+#define AIC7XXX_C_VERSION  "5.1.7"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -580,6 +580,7 @@ static const char *board_names[] = {
   "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
   "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
   "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
 };
 
@@ -5815,23 +5816,19 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       * We know that this particular SCB had to be the queued abort since
-       * the disconnected SCB would have gotten a reconnect instead.
-       * However, if this is an abort command, then DID_TIMEOUT isn't
-       * appropriate, neither is returning the command for that matter.
-       * What we need to do then is to let the command timeout again so
-       * we get a reset since this abort just failed.
-       */
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
       if (aic7xxx_verbose > 0xffff)
         printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
 #endif
-      if (p->flags & SCB_QUEUED_ABORT)
+      if (scb->flags & SCB_QUEUED_ABORT)
       {
+        /*
+         * We know that this particular SCB had to be the queued abort since
+         * the disconnected SCB would have gotten a reconnect instead.
+         * What we need to do then is to let the command timeout again so
+         * we get a reset since this abort just failed.
+         */
         cmd->result = 0;
-        scb->flags &= ~SCB_QUEUED_ABORT;
         scb = NULL;
       }
     }
@@ -7659,7 +7656,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+    aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
          ENSTIMER | ACTNEGEN, SXFRCTL1);
     aic_outb(p, 0, SIMODE0);
     aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -7676,7 +7673,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     aic_outb(p, p->scsi_id, SCSIID);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-  aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+  aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
        ENSTIMER | ACTNEGEN, SXFRCTL1);
   aic_outb(p, 0, SIMODE0);
   aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -8856,9 +8853,13 @@ aic7xxx_detect(Scsi_Host_Template *template)
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
        AHC_AIC7896_FE,                                      23,
        32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      24,
+       32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                      24,
+       AHC_AIC7860_FE,                                      25,
        32, C46 },
     };
 
@@ -9104,6 +9105,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
             case 15:
             case 18:
             case 19:
+            case 20:
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
@@ -9271,13 +9273,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
           }
 
           /*
-           * We do another switch based on i so that we can exclude all
-           * 3895 devices from the next option since the 3895 cards use
-           * shared external SCB RAM while all other cards have dedicated
-           * external SCB RAM per channel.  Also exclude the 7850 and
-           * 7860 based stuff since they can have garbage in the bit
-           * that indicates external RAM and get some of this stuff
-           * wrong as a result.
+           * We only support external SCB RAM on the 7895/6/7 chipsets.
+           * We could support it on the 7890/1 easy enough, but I don't
+           * know of any 7890/1 based cards that have it.  I do know
+           * of 7895/6/7 cards that have it and they work properly.
            */
           switch(temp_p->chip & AHC_CHIPID_MASK)
           {
index d9eda89f1e2b9ca111b4032b06df299e6e48b1eb..762cdff6bb68c01793a5c00585e620f965ea82ce 100644 (file)
@@ -69,8 +69,6 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
                   int hostno, int inout)
 {
 
-#ifdef CONFIG_PROC_FS
-
     Scsi_Device *scd, SDev;
     struct Scsi_Host *HBA_ptr;
     Scsi_Cmnd scmd;
@@ -469,9 +467,6 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
     DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
     return (len);     
-#else /* CONFIG_PROC_FS */
-    return 0;
-#endif        
 }
 
 /*
index 4ccc65182233b12cc2a3dc667931ef6555e94645..4023c184e85fd28d450c31639a19b2a0a94c07b1 100644 (file)
@@ -26,7 +26,6 @@ int eata_pio_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
 int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length, 
                       int hostno, int inout)
 {
-#ifdef CONFIG_PROC_FS
     Scsi_Device *scd;
     struct Scsi_Host *HBA_ptr;
     static u8 buff[512];
@@ -110,9 +109,6 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
     DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
     return (len);     
-#else
-    return 0;
-#endif        
 }
 
 /*
index 689ddb0743c58ccc6fef1ba96d52fe62cc796d90..8141a6c1e242026fc1d2fb0859cb86bd8a158070 100644 (file)
@@ -4,8 +4,7 @@
  * (The IMM is the embedded controller in the ZIP Plus drive.)
  * 
  * Current Maintainer: David Campbell (Perth, Western Australia)
- *                     campbell@gear.torque.net
- *                     dcampbel@p01.as17.honeywell.com.au
+ *                     campbell@torque.net
  *
  * My unoffical company acronym list is 21 pages long:
  *      FLA:    Four letter acronym with built in facility for
@@ -31,7 +30,7 @@ static int device_check(int host_no);
 #include "sd.h"
 #include "hosts.h"
 typedef struct {
-    struct pardevice *dev;      /* Parport device entry         */
+    struct pardevice *dev;     /* Parport device entry         */
     int base;                  /* Actual port address          */
     int mode;                  /* Transfer mode                */
     int host;                  /* Host number (for proc)       */
@@ -65,23 +64,24 @@ static imm_struct imm_hosts[NO_HOSTS] =
 
 #define IMM_BASE(x)    imm_hosts[(x)].base
 
-int parbus_base[NO_HOSTS] = {0x03bc, 0x0378, 0x0278, 0x0000};
+int parbus_base[NO_HOSTS] =
+{0x03bc, 0x0378, 0x0278, 0x0000};
 
 void imm_wakeup(void *ref)
 {
     imm_struct *imm_dev = (imm_struct *) ref;
 
     if (!imm_dev->p_busy)
-        return;
+       return;
 
     if (parport_claim(imm_dev->dev)) {
-        printk("imm: bug in imm_wakeup\n");
-        return;
+       printk("imm: bug in imm_wakeup\n");
+       return;
     }
     imm_dev->p_busy = 0;
     imm_dev->base = imm_dev->dev->port->base;
     if (imm_dev->cur_cmd)
-        imm_dev->cur_cmd->SCp.phase++;
+       imm_dev->cur_cmd->SCp.phase++;
     return;
 }
 
@@ -97,12 +97,11 @@ int imm_release(struct Scsi_Host *host)
 static int imm_pb_claim(int host_no)
 {
     if (parport_claim(imm_hosts[host_no].dev)) {
-        imm_hosts[host_no].p_busy = 1;
-        return 1;
+       imm_hosts[host_no].p_busy = 1;
+       return 1;
     }
-
     if (imm_hosts[host_no].cur_cmd)
-        imm_hosts[host_no].cur_cmd->SCp.phase++;
+       imm_hosts[host_no].cur_cmd->SCp.phase++;
     return 0;
 }
 
@@ -112,40 +111,7 @@ static int imm_pb_claim(int host_no)
  *                   Parallel port probing routines                        *
  ***************************************************************************/
 
-#ifndef MODULE
-/*
- * Command line parameters (for built-in driver):
- *
- * Syntax:  imm=base[,mode[,use_sg]]
- *
- * For example:  imm=0x378   or   imm=0x378,0,3
- *
- */
-
-void imm_setup(char *str, int *ints)
-{
-    static int x = 0;
-
-    if (x == 0) {              /* Disable ALL known ports */
-       int i;
-
-       for (i = 0; i < NO_HOSTS; i++)
-           parbus_base[i] = 0x0000;
-    }
-    switch (ints[0]) {
-    case 3:
-       imm_sg = ints[3];
-    case 2:
-       imm_hosts[x].mode = ints[2];
-       parbus_base[x] = ints[1];
-       break;
-    default:
-       printk("IMM: I only use between 2 to 3 parameters.\n");
-       break;
-    }
-    x++;
-}
-#else
+#ifdef MODULE
 Scsi_Host_Template driver_template = IMM;
 #include  "scsi_module.c"
 #endif
@@ -162,100 +128,95 @@ int imm_detect(Scsi_Host_Template * host)
     try_again = 0;
 
     if (!pb) {
-        printk("imm: parport reports no devices.\n");
-        return 0;
+       printk("imm: parport reports no devices.\n");
+       return 0;
     }
-
   retry_entry:
     for (i = 0; pb; i++, pb = pb->next) {
-        int modes, ppb;
+       int modes, ppb;
 
-        imm_hosts[i].dev =
-            parport_register_device(pb, "imm", NULL, imm_wakeup,
-                         NULL, 0, (void *) &imm_hosts[i]);
+       imm_hosts[i].dev =
+           parport_register_device(pb, "imm", NULL, imm_wakeup,
+                                   NULL, 0, (void *) &imm_hosts[i]);
 
        if (!imm_hosts[i].dev)
-               continue;
+           continue;
 
-        /* Claim the bus so it remembers what we do to the control
-         * registers. [ CTR and ECP ]
-         */
-       if (imm_pb_claim(i))
-       {
+       /* Claim the bus so it remembers what we do to the control
+        * registers. [ CTR and ECP ]
+        */
+       if (imm_pb_claim(i)) {
            unsigned long now = jiffies;
-           while (imm_hosts[i].p_busy)
-           {
+           while (imm_hosts[i].p_busy) {
                schedule();     /* We are safe to schedule here */
-               if (time_after(jiffies,now + 3*HZ))
-               {
+               if (time_after(jiffies, now + 3 * HZ)) {
                    printk(KERN_ERR "imm%d: failed to claim parport because a "
-                          "pardevice is owning the port for too longtime!\n",
+                     "pardevice is owning the port for too longtime!\n",
                           i);
                    return 0;
                }
            }
        }
+       ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;
+       w_ctr(ppb, 0x0c);
+       modes = imm_hosts[i].dev->port->modes;
+
+       /* Mode detection works up the chain of speed
+        * This avoids a nasty if-then-else-if-... tree
+        */
+       imm_hosts[i].mode = IMM_NIBBLE;
+
+       if (modes & PARPORT_MODE_PCPS2)
+           imm_hosts[i].mode = IMM_PS2;
+
+       if (modes & PARPORT_MODE_PCECPPS2) {
+           w_ecr(ppb, 0x20);
+           imm_hosts[i].mode = IMM_PS2;
+       }
+       if (modes & PARPORT_MODE_PCECPEPP)
+           w_ecr(ppb, 0x80);
+
+       /* Done configuration */
+       imm_pb_release(i);
 
-        ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;
-        w_ctr(ppb, 0x0c);
-        modes = imm_hosts[i].dev->port->modes;
-
-        /* Mode detection works up the chain of speed
-         * This avoids a nasty if-then-else-if-... tree
-         */
-        imm_hosts[i].mode = IMM_NIBBLE;
-
-        if (modes & PARPORT_MODE_PCPS2)
-            imm_hosts[i].mode = IMM_PS2;
-
-        if (modes & PARPORT_MODE_PCECPPS2) {
-            w_ecr(ppb, 0x20);
-            imm_hosts[i].mode = IMM_PS2;
-        }
-        if (modes & PARPORT_MODE_PCECPEPP)
-            w_ecr(ppb, 0x80);
-
-        /* Done configuration */
-        imm_pb_release(i);
-
-        if (imm_init(i)) {
-            parport_unregister_device(imm_hosts[i].dev);
-            continue;
-        }
-        /* now the glue ... */
-        switch (imm_hosts[i].mode) {
-        case IMM_NIBBLE:
-            ports = 3;
-            break;
-        case IMM_PS2:
-            ports = 3;
-            break;
-        case IMM_EPP_8:
-        case IMM_EPP_16:
-        case IMM_EPP_32:
-            ports = 8;
-            break;
-        default:                /* Never gets here */
-            continue;
-        }
-
-        host->can_queue = IMM_CAN_QUEUE;
-        host->sg_tablesize = imm_sg;
-        hreg = scsi_register(host, 0);
-        hreg->io_port = pb->base;
-        hreg->n_io_port = ports;
-        hreg->dma_channel = -1;
-        hreg->unique_id = i;
-        imm_hosts[i].host = hreg->host_no;
-        nhosts++;
+       if (imm_init(i)) {
+           parport_unregister_device(imm_hosts[i].dev);
+           continue;
+       }
+       /* now the glue ... */
+       switch (imm_hosts[i].mode) {
+       case IMM_NIBBLE:
+           ports = 3;
+           break;
+       case IMM_PS2:
+           ports = 3;
+           break;
+       case IMM_EPP_8:
+       case IMM_EPP_16:
+       case IMM_EPP_32:
+           ports = 8;
+           break;
+       default:                /* Never gets here */
+           continue;
+       }
+
+       host->can_queue = IMM_CAN_QUEUE;
+       host->sg_tablesize = imm_sg;
+       hreg = scsi_register(host, 0);
+       hreg->io_port = pb->base;
+       hreg->n_io_port = ports;
+       hreg->dma_channel = -1;
+       hreg->unique_id = i;
+       imm_hosts[i].host = hreg->host_no;
+       nhosts++;
     }
     if (nhosts == 0) {
-        if (try_again == 1)
-            return 0;
-        try_again = 1;
-        goto retry_entry;
+       if (try_again == 1)
+           return 0;
+       try_again = 1;
+       goto retry_entry;
     } else
-        return 1;               /* return number of hosts detected */
+       return 1;               /* return number of hosts detected */
 }
 
 /* This is to give the imm driver a way to modify the timings (and other
@@ -265,22 +226,11 @@ int imm_detect(Scsi_Host_Template * host)
  * testing...
  * Also gives a method to use a script to obtain optimum timings (TODO)
  */
-
-static inline int imm_strncmp(const char *a, const char *b, int len)
-{
-    int loop;
-    for (loop = 0; loop < len; loop++)
-       if (a[loop] != b[loop])
-           return 1;
-
-    return 0;
-}
-
 static inline int imm_proc_write(int hostno, char *buffer, int length)
 {
     unsigned long x;
 
-    if ((length > 5) && (imm_strncmp(buffer, "mode=", 5) == 0)) {
+    if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
        x = simple_strtoul(buffer + 5, NULL, 0);
        imm_hosts[hostno].mode = x;
        return length;
@@ -445,42 +395,34 @@ static inline void ecp_sync(unsigned short ppb)
     int i;
 
     if ((r_ecr(ppb) & 0xe0) != 0x80)
-        return;
+       return;
 
     for (i = 0; i < 100; i++) {
-        if (r_ecr(ppb) & 0x01)
-            return;
-        udelay(5);
+       if (r_ecr(ppb) & 0x01)
+           return;
+       udelay(5);
     }
     printk("imm: ECP sync failed as data still present in FIFO.\n");
 }
 
-static inline int imm_byte_out(unsigned short base, const char *buffer, int len)
+static int imm_byte_out(unsigned short base, const char *buffer, int len)
 {
     int i;
 
-    w_ctr(base, 0x4);          /* aimmrently a sane mode */
+    w_ctr(base, 0x4);          /* apparently a sane mode */
     for (i = len >> 1; i; i--) {
        w_dtr(base, *buffer++);
        w_ctr(base, 0x5);       /* Drop STROBE low */
        w_dtr(base, *buffer++);
        w_ctr(base, 0x0);       /* STROBE high + INIT low */
     }
-    w_ctr(base, 0x4);          /* aimmrently a sane mode */
+    w_ctr(base, 0x4);          /* apparently a sane mode */
     return 1;                  /* All went well - we hope! */
 }
 
-static inline int imm_epp_out(unsigned short base, char *buffer, int len)
+static int imm_nibble_in(unsigned short base, char *buffer, int len)
 {
-    int i;
-    for (i = len; i; i--)
-       w_epp(base, *buffer++);
-    return 1;
-}
-
-static inline int imm_nibble_in(unsigned short base, char *buffer, int len)
-{
-    unsigned char h, l;
+    unsigned char l;
     int i;
 
     /*
@@ -489,16 +431,15 @@ static inline int imm_nibble_in(unsigned short base, char *buffer, int len)
     w_ctr(base, 0x4);
     for (i = len; i; i--) {
        w_ctr(base, 0x6);
-       l = r_str(base);
+       l = (r_str(base) & 0xf0) >> 4;
        w_ctr(base, 0x5);
-       h = r_str(base);
+       *buffer++ = (r_str(base) & 0xf0) | l;
        w_ctr(base, 0x4);
-       *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
     }
     return 1;                  /* All went well - we hope! */
 }
 
-static inline int imm_byte_in(unsigned short base, char *buffer, int len)
+static int imm_byte_in(unsigned short base, char *buffer, int len)
 {
     int i;
 
@@ -514,14 +455,6 @@ static inline int imm_byte_in(unsigned short base, char *buffer, int len)
     return 1;                  /* All went well - we hope! */
 }
 
-static inline int imm_epp_in(unsigned short base, char *buffer, int len)
-{
-    int i;
-    for (i = len; i; i--)
-       *buffer++ = r_epp(base);
-    return 1;
-}
-
 static int imm_out(int host_no, char *buffer, int len)
 {
     int r;
@@ -543,11 +476,21 @@ static int imm_out(int host_no, char *buffer, int len)
     case IMM_EPP_32:
     case IMM_EPP_16:
     case IMM_EPP_8:
-        epp_reset(ppb);
-        w_ctr(ppb, 0x4);
-       r = imm_epp_out(ppb, buffer, len);
-        w_ctr(ppb, 0xc);
-        ecp_sync(ppb);
+       epp_reset(ppb);
+       w_ctr(ppb, 0x4);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+       if (!(((long) buffer | len) & 0x01))
+           outsw(ppb + 4, buffer, len >> 1);
+#else
+       if (!(((long) buffer | len) & 0x03))
+           outsl(ppb + 4, buffer, len >> 2);
+#endif
+       else
+           outsb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0xc);
+       r = !(r_str(ppb) & 0x01);
+       w_ctr(ppb, 0xc);
+       ecp_sync(ppb);
        break;
 
     case IMM_NIBBLE:
@@ -595,11 +538,21 @@ static int imm_in(int host_no, char *buffer, int len)
     case IMM_EPP_32:
     case IMM_EPP_16:
     case IMM_EPP_8:
-        epp_reset(ppb);
-        w_ctr(ppb, 0x24);
-       r = imm_epp_in(ppb, buffer, len);
-        w_ctr(ppb, 0x2c);
-        ecp_sync(ppb);
+       epp_reset(ppb);
+       w_ctr(ppb, 0x24);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+       if (!(((long) buffer | len) & 0x01))
+           insw(ppb + 4, buffer, len >> 1);
+#else
+       if (!(((long) buffer | len) & 0x03))
+           insl(ppb + 4, buffer, len >> 2);
+#endif
+       else
+           insb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0x2c);
+       r = !(r_str(ppb) & 0x01);
+       w_ctr(ppb, 0x2c);
+       ecp_sync(ppb);
        break;
 
     default:
@@ -756,8 +709,8 @@ static int imm_init(int host_no)
 
 #if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE)
     if (imm_pb_claim(host_no))
-        while (imm_hosts[host_no].p_busy)
-            schedule();         /* We can safe schedule here */
+       while (imm_hosts[host_no].p_busy)
+           schedule();         /* We can safe schedule here */
 #endif
     retv = imm_connect(host_no, 0);
 
@@ -770,7 +723,6 @@ static int imm_init(int host_no)
        imm_pb_release(host_no);
        return retv;
     }
-
     imm_pb_release(host_no);
     return 1;
 }
@@ -831,7 +783,7 @@ static int imm_completion(Scsi_Cmnd * cmd)
         * If we have been running for more than a full timer tick
         * then take a rest.
         */
-       if (time_after(jiffies,start_jiffies + 1))
+       if (time_after(jiffies, start_jiffies + 1))
            return 0;
 
        /*
@@ -1173,6 +1125,7 @@ int imm_biosparam(Disk * disk, kdev_t dev, int ip[])
 
 int imm_abort(Scsi_Cmnd * cmd)
 {
+    int host_no = cmd->host->unique_id;
     /*
      * There is no method for aborting commands since Iomega
      * have tied the SCSI_MESSAGE line high in the interface
@@ -1181,12 +1134,11 @@ int imm_abort(Scsi_Cmnd * cmd)
     switch (cmd->SCp.phase) {
     case 0:                    /* Do not have access to parport */
     case 1:                    /* Have not connected to interface */
-       cmd->result = DID_ABORT;
-       cmd->done(cmd);
-       return SCSI_ABORT_SUCCESS;
+       imm_hosts[host_no].cur_cmd = NULL;      /* Forget the problem */
+       return SUCCESS;
        break;
     default:                   /* SCSI command sent, can not abort */
-       return SCSI_ABORT_BUSY;
+       return FAILED;
        break;
     }
 }
@@ -1203,46 +1155,20 @@ void imm_reset_pulse(unsigned int base)
     w_ctr(base, 0x04);
 }
 
-int imm_reset(Scsi_Cmnd * cmd, unsigned int x)
+int imm_reset(Scsi_Cmnd * cmd)
 {
     int host_no = cmd->host->unique_id;
 
-    /*
-     * PHASE1:
-     * Bring the interface crashing down on whatever is running
-     * hopefully this will kill the request.
-     * Bring back up the interface, reset the drive (and anything
-     * attached for that manner)
-     */
-    if (cmd)
-       if (cmd->SCp.phase)
-           imm_disconnect(cmd->host->unique_id);
+    if (cmd->SCp.phase)
+       imm_disconnect(host_no);
+    imm_hosts[host_no].cur_cmd = NULL; /* Forget the problem */
 
     imm_connect(host_no, CONNECT_NORMAL);
     imm_reset_pulse(IMM_BASE(host_no));
-    udelay(1000);              /* delay for devices to settle down */
+    udelay(1000);              /* device settle delay */
     imm_disconnect(host_no);
-    udelay(1000);              /* Additional delay to allow devices to settle down */
-
-    /*
-     * PHASE2:
-     * Sanity check for the sake of mid-level driver
-     */
-    if (!cmd) {
-       printk("imm bus reset called for invalid command.\n");
-       return SCSI_RESET_NOT_RUNNING;
-    }
-    /*
-     * PHASE3:
-     * Flag the current command as having died due to reset
-     */
-    imm_connect(host_no, CONNECT_NORMAL);
-    imm_fail(host_no, DID_RESET);
-
-    /* Since the command was already on the timer queue imm_interrupt
-     * will be called shortly.
-     */
-    return SCSI_RESET_PENDING;
+    udelay(1000);              /* device settle delay */
+    return SUCCESS;
 }
 
 static int device_check(int host_no)
@@ -1257,79 +1183,78 @@ static int device_check(int host_no)
 
     old_mode = imm_hosts[host_no].mode;
     for (loop = 0; loop < 8; loop++) {
-        /* Attempt to use EPP for Test Unit Ready */
-        if ((ppb & 0x0007) == 0x0000)
-            imm_hosts[host_no].mode = IMM_EPP_32;
+       /* Attempt to use EPP for Test Unit Ready */
+       if ((ppb & 0x0007) == 0x0000)
+           imm_hosts[host_no].mode = IMM_EPP_32;
 
       second_pass:
-        imm_connect(host_no, CONNECT_EPP_MAYBE);
-        /* Select SCSI device */
-        if (!imm_select(host_no, loop)) {
-            imm_disconnect(host_no);
-            continue;
-        }
-        printk("imm: Found device at ID %i, Attempting to use %s\n", loop,
-               IMM_MODE_STRING[imm_hosts[host_no].mode]);
-
-        /* Send SCSI command */
-        status = 1;
-        w_ctr(ppb, 0x0c);
-        for (l = 0; (l < 3) && (status); l++)
-            status = imm_out(host_no, &cmd[l<<1], 2);
-
-        if (!status) {
-            imm_disconnect(host_no);
-            imm_connect(host_no, CONNECT_EPP_MAYBE);
-            w_dtr(ppb, 0x40);
-            w_ctr(ppb, 0x08);
-            udelay(30);
-            w_ctr(ppb, 0x0c);
-            udelay(1000);
-            imm_disconnect(host_no);
-            udelay(1000);
-            if (imm_hosts[host_no].mode == IMM_EPP_32) {
-                imm_hosts[host_no].mode = old_mode;
-                goto second_pass;
-            }
-            printk("imm: Unable to establish communication, aborting driver load.\n");
-            return 1;
-        }
-        w_ctr(ppb, 0x0c);
-
-        k = 1000000;            /* 1 Second */
-        do {
-            l = r_str(ppb);
-            k--;
-            udelay(1);
-        } while (!(l & 0x80) && (k));
-
-        l &= 0xb8;
-
-        if (l != 0xb8) {
-            imm_disconnect(host_no);
-            imm_connect(host_no, CONNECT_EPP_MAYBE);
+       imm_connect(host_no, CONNECT_EPP_MAYBE);
+       /* Select SCSI device */
+       if (!imm_select(host_no, loop)) {
+           imm_disconnect(host_no);
+           continue;
+       }
+       printk("imm: Found device at ID %i, Attempting to use %s\n", loop,
+              IMM_MODE_STRING[imm_hosts[host_no].mode]);
+
+       /* Send SCSI command */
+       status = 1;
+       w_ctr(ppb, 0x0c);
+       for (l = 0; (l < 3) && (status); l++)
+           status = imm_out(host_no, &cmd[l << 1], 2);
+
+       if (!status) {
+           imm_disconnect(host_no);
+           imm_connect(host_no, CONNECT_EPP_MAYBE);
+           w_dtr(ppb, 0x40);
+           w_ctr(ppb, 0x08);
+           udelay(30);
+           w_ctr(ppb, 0x0c);
+           udelay(1000);
+           imm_disconnect(host_no);
+           udelay(1000);
+           if (imm_hosts[host_no].mode == IMM_EPP_32) {
+               imm_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("imm: Unable to establish communication, aborting driver load.\n");
+           return 1;
+       }
+       w_ctr(ppb, 0x0c);
+
+       k = 1000000;            /* 1 Second */
+       do {
+           l = r_str(ppb);
+           k--;
+           udelay(1);
+       } while (!(l & 0x80) && (k));
+
+       l &= 0xb8;
+
+       if (l != 0xb8) {
+           imm_disconnect(host_no);
+           imm_connect(host_no, CONNECT_EPP_MAYBE);
            imm_reset_pulse(IMM_BASE(host_no));
-            udelay(1000);
-            imm_disconnect(host_no);
-            udelay(1000);
-            if (imm_hosts[host_no].mode == IMM_EPP_32) {
-                imm_hosts[host_no].mode = old_mode;
-                goto second_pass;
-            }
-            printk("imm: Unable to establish communication, aborting driver load.\n");
-            return 1;
-        }
-        imm_disconnect(host_no);
-        printk("imm: Communication established with ID %i using %s\n", loop,
-               IMM_MODE_STRING[imm_hosts[host_no].mode]);
-        imm_connect(host_no, CONNECT_EPP_MAYBE);
+           udelay(1000);
+           imm_disconnect(host_no);
+           udelay(1000);
+           if (imm_hosts[host_no].mode == IMM_EPP_32) {
+               imm_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("imm: Unable to establish communication, aborting driver load.\n");
+           return 1;
+       }
+       imm_disconnect(host_no);
+       printk("imm: Communication established with ID %i using %s\n", loop,
+              IMM_MODE_STRING[imm_hosts[host_no].mode]);
+       imm_connect(host_no, CONNECT_EPP_MAYBE);
        imm_reset_pulse(IMM_BASE(host_no));
-        udelay(1000);
-        imm_disconnect(host_no);
-        udelay(1000);
-        return 0;
+       udelay(1000);
+       imm_disconnect(host_no);
+       udelay(1000);
+       return 0;
     }
     printk("imm: No devices found, aborting driver load.\n");
     return 1;
 }
-
index 2818603dda329d2de96e51a269f24a580c1c3af8..87f724e058fb2dda120712f2f729bf43301d5718 100644 (file)
@@ -1,7 +1,8 @@
+
 /*  Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in 
  * the Iomega ZIP Plus drive
  * 
- * (c) 1998     David Campbell    campbell@torque.net
+ * (c) 1998     David Campbell     campbell@torque.net
  *
  * Please note that I live in Perth, Western Australia. GMT+0800
  */
 #ifndef _IMM_H
 #define _IMM_H
 
-#define   IMM_VERSION   "2.00"
+#define   IMM_VERSION   "2.03 (for Linux 2.0.0)"
 
 /* 
  * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega.
  * Scarry thing is the level of support from one of their managers.
  * The onus is now on us (the developers) to shut up and start coding.
- *                                             11Apr98 [ 0.10 ]
+ *                                              11Apr98 [ 0.10 ]
  *
  * --- SNIP ---
  *
  * Removing "Phase" debug messages.
  *
  * PS: Took four hours of coding after I bought a drive.
- *     ANZAC Day (Aus "War Veterans Holiday")  25Apr98 [ 0.14 ]
+ *      ANZAC Day (Aus "War Veterans Holiday")  25Apr98 [ 0.14 ]
  *
  * Ten minutes later after a few fixes.... (LITERALLY!!!)
  * Have mounted disk, copied file, dismounted disk, remount disk, diff file
  *                    -----  It actually works!!! -----
- *                                             25Apr98 [ 0.15 ]
+ *                                              25Apr98 [ 0.15 ]
  *
  * Twenty minutes of mucking around, rearanged the IEEE negotiate mechanism.
  * Now have byte mode working (only EPP and ECP to go now... :=)
- *                                             26Apr98 [ 0.16 ]
+ *                                              26Apr98 [ 0.16 ]
  *
  * Thirty minutes of further coding results in EPP working on my machine.
- *                                             27Apr98 [ 0.17 ]
+ *                                              27Apr98 [ 0.17 ]
  *
  * Due to work commitments and inability to get a "true" ECP mode functioning
  * I have decided to code the parport support into imm.
- *                                             09Jun98 [ 0.18 ]
+ *                                              09Jun98 [ 0.18 ]
  *
  * Driver is now out of beta testing.
  * Support for parport has been added.
  * Now distributed with the ppa driver.
- *                                             12Jun98 [ 2.00 ]
+ *                                              12Jun98 [ 2.00 ]
  *
  * Err.. It appears that imm-2.00 was broken....
- *                                             18Jun98 [ 2.01 ]
+ *                                              18Jun98 [ 2.01 ]
  *
  * Patch applied to sync this against the Linux 2.1.x kernel code
  * Included qboot_zip.sh
- *                                             21Jun98 [ 2.02 ]
+ *                                              21Jun98 [ 2.02 ]
+ *
+ * Other clean ups include the follow changes:
+ *    CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
+ *    added CONFIG_SCSI_IZIP_SLOW_CTR option
+ *                                                      [2.03]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
@@ -92,7 +98,11 @@ static char *IMM_MODE_STRING[] =
     "PS/2",
     "EPP 8 bit",
     "EPP 16 bit",
+#ifdef CONFIG_SCSI_IZIP_EPP16
+    "EPP 16 bit",
+#else
     "EPP 32 bit",
+#endif
     "Unknown"};
 
 /* This is a global option */
@@ -110,21 +120,24 @@ int imm_sg = SG_ALL;              /* enable/disable scatter-gather. */
 #define CONNECT_EPP_MAYBE 1
 #define CONNECT_NORMAL  0
 
-#define inb_x inb
-#define r_dtr(x)        (unsigned char)inb_x((x))
-#define r_str(x)        (unsigned char)inb_x((x)+1)
-#define r_ctr(x)        (unsigned char)inb_x((x)+2)
-#define r_epp(x)        (unsigned char)inb_x((x)+4)
-#define r_fifo(x)       (unsigned char)inb_x((x)+0x400)
-#define r_ecr(x)        (unsigned char)inb_x((x)+0x402)
-
-#define outb_x outb
-#define w_dtr(x,y)      outb_x(y, (x))
-#define w_str(x,y)      outb_x(y, (x)+1)
-#define w_ctr(x,y)      outb_x(y, (x)+2)
-#define w_epp(x,y)      outb_x(y, (x)+4)
-#define w_fifo(x,y)     outb_x(y, (x)+0x400)
-#define w_ecr(x,y)      outb_x(y, (x)+0x402)
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb((x)+0x402)
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x)+0x400)
+#define w_ecr(x,y)      outb(y, (x)+0x402)
+
+#ifdef CONFIG_SCSI_IZIP_SLOW_CTR
+#define w_ctr(x,y)      outb_p(y, (x)+2)
+#else
+#define w_ctr(x,y)      outb(y, (x)+2)
+#endif
 
 static int imm_engine(imm_struct *, Scsi_Cmnd *);
 static int imm_in(int, char *, int);
@@ -144,23 +157,25 @@ const char *imm_info(struct Scsi_Host *);
 int imm_command(Scsi_Cmnd *);
 int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int imm_abort(Scsi_Cmnd *);
-int imm_reset(Scsi_Cmnd *, unsigned int);
+int imm_reset(Scsi_Cmnd *);
 int imm_proc_info(char *, char **, off_t, int, int, int);
 int imm_biosparam(Disk *, kdev_t, int *);
 
-#define IMM {  proc_dir:               &proc_scsi_imm,                 \
-               proc_info:              imm_proc_info,                  \
-               name:                   "Iomega ZIP Plus drive",        \
-               detect:                 imm_detect,                     \
-               release:                imm_release,                    \
-               command:                imm_command,                    \
-               queuecommand:           imm_queuecommand,               \
-               abort:                  imm_abort,                      \
-               reset:                  imm_reset,                      \
-               bios_param:             imm_biosparam,                  \
-               this_id:                7,                              \
-               sg_tablesize:           SG_ALL,                         \
-               cmd_per_lun:            1,                              \
-               use_clustering:         ENABLE_CLUSTERING               \
+#define IMM {  proc_dir:                       &proc_scsi_imm,         \
+               proc_info:                      imm_proc_info,          \
+               name:                           "Iomega VPI2 (imm) interface",\
+               detect:                         imm_detect,             \
+               release:                        imm_release,            \
+               command:                        imm_command,            \
+               queuecommand:                   imm_queuecommand,       \
+                eh_abort_handler:               imm_abort,              \
+                eh_device_reset_handler:        NULL,                   \
+                eh_bus_reset_handler:           imm_reset,              \
+                eh_host_reset_handler:          imm_reset,              \
+               bios_param:                     imm_biosparam,          \
+               this_id:                        7,                      \
+               sg_tablesize:                   SG_ALL,                 \
+               cmd_per_lun:                    1,                      \
+               use_clustering:                 ENABLE_CLUSTERING       \
 }
 #endif                         /* _IMM_H */
index 920e90a4b6f8d77992bebba07cc83cc06bb99541..e6ffc6189b62cbdafafef349122dcf41dd87d17a 100644 (file)
@@ -7,8 +7,7 @@
  * under the terms of the GNU Public License.
  * 
  * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
- *                     campbell@gear.torque.net
- *                     dcampbel@p01.as17.honeywell.com.au
+ *                     campbell@torque.net
  */
 
 #include <linux/config.h>
@@ -68,7 +67,6 @@ void ppa_wakeup(void *ref)
        printk("ppa: bug in ppa_wakeup\n");
        return;
     }
-
     ppa_dev->p_busy = 0;
     ppa_dev->base = ppa_dev->dev->port->base;
     if (ppa_dev->cur_cmd)
@@ -91,7 +89,6 @@ static int ppa_pb_claim(int host_no)
        ppa_hosts[host_no].p_busy = 1;
        return 1;
     }
-
     if (ppa_hosts[host_no].cur_cmd)
        ppa_hosts[host_no].cur_cmd->SCp.phase++;
     return 0;
@@ -133,30 +130,26 @@ int ppa_detect(Scsi_Host_Template * host)
 
        ppa_hosts[i].dev =
            parport_register_device(pb, "ppa", NULL, ppa_wakeup,
-                        NULL, 0, (void *) &ppa_hosts[i]);
+                                   NULL, 0, (void *) &ppa_hosts[i]);
 
        if (!ppa_hosts[i].dev)
-               continue;
+           continue;
 
        /* Claim the bus so it remembers what we do to the control
         * registers. [ CTR and ECP ]
         */
-       if (ppa_pb_claim(i))
-       {
+       if (ppa_pb_claim(i)) {
            unsigned long now = jiffies;
-           while (ppa_hosts[i].p_busy)
-           {
+           while (ppa_hosts[i].p_busy) {
                schedule();     /* We are safe to schedule here */
-               if (time_after(jiffies,now + 3*HZ))
-               {
+               if (time_after(jiffies, now + 3 * HZ)) {
                    printk(KERN_ERR "ppa%d: failed to claim parport because a "
-                          "pardevice is owning the port for too longtime!\n",
+                     "pardevice is owning the port for too longtime!\n",
                           i);
                    return 0;
                }
            }
        }
-
        ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base;
        w_ctr(ppb, 0x0c);
        modes = ppa_hosts[i].dev->port->modes;
@@ -211,8 +204,15 @@ int ppa_detect(Scsi_Host_Template * host)
        nhosts++;
     }
     if (nhosts == 0) {
-       if (try_again == 1)
+       if (try_again == 1) {
+           printk("WARNING - no ppa compatible devices found.\n");
+           printk("  As of 31/Aug/1998 Iomega started shipping parallel\n");
+           printk("  port ZIP drives with a different interface which is\n");
+           printk("  supported by the imm (ZIP Plus) driver. If the\n");
+           printk("  cable is marked with \"AutoDetect\", this is what has\n");
+           printk("  happened.\n");
            return 0;
+       }
        try_again = 1;
        goto retry_entry;
     } else
@@ -227,21 +227,11 @@ int ppa_detect(Scsi_Host_Template * host)
  * Also gives a method to use a script to obtain optimum timings (TODO)
  */
 
-static inline int ppa_strncmp(const char *a, const char *b, int len)
-{
-    int loop;
-    for (loop = 0; loop < len; loop++)
-       if (a[loop] != b[loop])
-           return 1;
-
-    return 0;
-}
-
 static inline int ppa_proc_write(int hostno, char *buffer, int length)
 {
     unsigned long x;
 
-    if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) {
+    if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
        x = simple_strtoul(buffer + 5, NULL, 0);
        ppa_hosts[hostno].mode = x;
        return length;
@@ -360,245 +350,42 @@ static inline void ecp_sync(unsigned short ppb)
     printk("ppa: ECP sync failed as data still present in FIFO.\n");
 }
 
-/*
- * Here is the asm code for the SPP/PS2 protocols for the i386.
- * This has been optimised for speed on 386/486 machines. There will
- * be very little improvement on the current 586+ machines as it is the
- * IO statements which will limit throughput.
- */
-#ifdef __i386__
-#define BYTE_OUT(reg) \
-       "       movb " #reg ",%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       addl $2,%%edx\n" \
-       "       movb $0x0e,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       movb $0x0c,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       subl $2,%%edx\n"
-
-static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int len)
-{
-    /*
-     * %eax scratch
-     * %ebx Data to transfer
-     * %ecx Counter (Don't touch!!)
-     * %edx Port
-     * %esi Source buffer (mem pointer)
-     *
-     * In case you are wondering what the last line of the asm does...
-     * <output allocation> : <input allocation> : <trashed registers>
-     */
-    register int d0;
-
-    asm("shr $2,%%ecx\n" \
-       "       jz .no_more_bulk_bo\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_bulk_bo:\n" \
-       "       movl (%%esi),%%ebx\n" \
-       BYTE_OUT(%%bl) \
-       BYTE_OUT(%%bh) \
-       "       rorl $16,%%ebx\n" \
-       BYTE_OUT(%%bl) \
-       BYTE_OUT(%%bh) \
-       "       addl $4,%%esi\n" \
-       "       loop .loop_bulk_bo\n" \
-       "       .p2align 4,,7\n" \
-       ".no_more_bulk_bo:" \
-  : "=S"(buffer), "=c"(d0)
-  : "1"(len), "d"(base), "0"(buffer)
-  : "eax", "ebx");
-
-    asm("andl $3,%%ecx\n" \
-       "       jz .no_more_loose_bo\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_loose_bo:\n" \
-       BYTE_OUT((%%esi)) \
-       "       incl %%esi\n" \
-       "       loop .loop_loose_bo\n" \
-       ".no_more_loose_bo:\n" \
-  : "=c"(d0)
-  : "0"(len), "d"(base), "S"(buffer)
-  : "eax", "ebx");
-    return 1;                  /* All went well - we hope! */
-}
-
-#define BYTE_IN(reg) \
-       "       inb (%%dx),%%al\n" \
-       "       movb %%al," #reg "\n" \
-       "       addl $2,%%edx\n" \
-       "       movb $0x27,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       movb $0x25,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       subl $2,%%edx\n"
-
-static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
-{
-    /*
-     * %eax scratch
-     * %ebx Data to transfer
-     * %ecx Counter (Don't touch!!)
-     * %edx Port
-     * %esi Source buffer (mem pointer)
-     *
-     * In case you are wondering what the last line of the asm does...
-     * <output allocation> : <input allocation> : <trashed registers>
-     */
-    register int d0;
-
-    asm("shr $2,%%ecx\n" \
-       "       jz .no_more_bulk_bi\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_bulk_bi:\n" \
-       BYTE_IN(%%bl) \
-       BYTE_IN(%%bh) \
-       "       rorl $16,%%ebx\n" \
-       BYTE_IN(%%bl) \
-       BYTE_IN(%%bh) \
-       "       rorl $16,%%ebx\n" \
-       "       movl %%ebx,(%%esi)\n" \
-       "       addl $4,%%esi\n" \
-       "       loop .loop_bulk_bi\n" \
-       "       .p2align 4,,7\n" \
-       ".no_more_bulk_bi:" \
-  : "=S"(buffer), "=c"(d0)
-  : "1"(len), "d"(base), "0"(buffer)
-  : "eax", "ebx");
-
-    asm("andl $3,%%ecx\n" \
-       "       jz .no_more_loose_bi\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_loose_bi:\n" \
-       BYTE_IN((%%esi)) \
-       "       incl %%esi\n" \
-       "       loop .loop_loose_bi\n" \
-       ".no_more_loose_bi:\n" \
-  : "=c"(d0)
-  : "0"(len), "d"(base), "S"(buffer)
-  : "eax", "ebx");
-    return 1;                  /* All went well - we hope! */
-}
-
-#define NIBBLE_IN(reg) \
-       "       incl %%edx\n" \
-       "       movb $0x04,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       decl %%edx\n" \
-       "       inb (%%dx),%%al\n" \
-       "       andb $0xf0,%%al\n" \
-       "       movb %%al," #reg "\n" \
-       "       incl %%edx\n" \
-       "       movb $0x06,%%al\n" \
-       "       outb %%al,(%%dx)\n" \
-       "       decl %%edx\n" \
-       "       inb (%%dx),%%al\n" \
-       "       shrb $4,%%al\n" \
-       "       orb %%al," #reg "\n"
-
-static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
-{
-    /*
-     * %eax scratch
-     * %ebx Data to transfer
-     * %ecx Counter (Don't touch!!)
-     * %edx Port
-     * %esi Source buffer (mem pointer)
-     *
-     * In case you are wondering what the last line of the asm does...
-     * <output allocation> : <input allocation> : <trashed registers>
-     */
-    register int d0;
-
-    asm("shr $2,%%ecx\n" \
-       "       jz .no_more_bulk_ni\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_bulk_ni:\n" \
-       NIBBLE_IN(%%bl) \
-       NIBBLE_IN(%%bh) \
-       "       rorl $16,%%ebx\n" \
-       NIBBLE_IN(%%bl) \
-       NIBBLE_IN(%%bh) \
-       "       rorl $16,%%ebx\n" \
-       "       movl %%ebx,(%%esi)\n" \
-       "       addl $4,%%esi\n" \
-       "       loop .loop_bulk_ni\n" \
-       "       .p2align 4,,7\n" \
-       ".no_more_bulk_ni:" \
-  : "=S"(buffer), "=c"(d0)
-  : "1"(len), "d"(str_p), "0"(buffer)
-  : "eax", "ebx");
-
-    asm("andl $3,%%ecx\n" \
-       "       jz .no_more_loose_ni\n" \
-       "       .p2align 4,,7\n" \
-       ".loop_loose_ni:\n" \
-       NIBBLE_IN((%%esi)) \
-       "       incl %%esi\n" \
-       "       loop .loop_loose_ni\n" \
-       ".no_more_loose_ni:\n" \
-  : "=c"(d0)
-  : "0"(len), "d"(str_p), "S"(buffer)
-  : "eax", "ebx");
-    return 1;                  /* All went well - we hope! */
-}
-#else                          /* Old style C routines */
-
-static inline int ppa_byte_out(unsigned short base, const char *buffer, int len)
+static int ppa_byte_out(unsigned short base, const char *buffer, int len)
 {
-    unsigned short ctr_p = base + 2;
     int i;
 
     for (i = len; i; i--) {
-       outb(*buffer++, base);
-       outb(0xe, ctr_p);
-       outb(0xc, ctr_p);
+       w_dtr(base, *buffer++);
+       w_ctr(base, 0xe);
+       w_ctr(base, 0xc);
     }
     return 1;                  /* All went well - we hope! */
 }
 
-static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
+static int ppa_byte_in(unsigned short base, char *buffer, int len)
 {
-    unsigned short ctr_p = base + 2;
     int i;
 
     for (i = len; i; i--) {
-       *buffer++ = inb(base);
-       outb(0x27, ctr_p);
-       outb(0x25, ctr_p);
+       *buffer++ = r_dtr(base);
+       w_ctr(base, 0x27);
+       w_ctr(base, 0x25);
     }
     return 1;                  /* All went well - we hope! */
 }
 
-static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+static int ppa_nibble_in(unsigned short base, char *buffer, int len)
 {
-    unsigned short ctr_p = str_p + 1;
-    unsigned char h, l;
-    int i;
+    for (; len; len--) {
+       unsigned char h;
 
-    for (i = len; i; i--) {
-       outb(0x4, ctr_p);
-       h = inb(str_p);
-       outb(0x6, ctr_p);
-       l = inb(str_p);
-       *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
+       w_ctr(base, 0x4);
+       h = r_str(base) & 0xf0;
+       w_ctr(base, 0x6);
+       *buffer++ = h | ((r_str(base) & 0xf0) >> 4);
     }
     return 1;                  /* All went well - we hope! */
 }
-#endif
-
-static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len)
-{
-    int i;
-    for (i = len; i; i--) {
-       outb(*buffer++, epp_p);
-#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
-       if (inb(str_p) & 0x01)
-           return 0;
-#endif
-    }
-    return 1;
-}
 
 static int ppa_out(int host_no, char *buffer, int len)
 {
@@ -623,16 +410,17 @@ static int ppa_out(int host_no, char *buffer, int len)
     case PPA_EPP_8:
        epp_reset(ppb);
        w_ctr(ppb, 0x4);
-#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
-       r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+       if (!(((long) buffer | len) & 0x01))
+           outsw(ppb + 4, buffer, len >> 1);
 #else
        if (!(((long) buffer | len) & 0x03))
            outsl(ppb + 4, buffer, len >> 2);
+#endif
        else
            outsb(ppb + 4, buffer, len);
        w_ctr(ppb, 0xc);
        r = !(r_str(ppb) & 0x01);
-#endif
        w_ctr(ppb, 0xc);
        ecp_sync(ppb);
        break;
@@ -644,19 +432,6 @@ static int ppa_out(int host_no, char *buffer, int len)
     return r;
 }
 
-static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len)
-{
-    int i;
-    for (i = len; i; i--) {
-       *buffer++ = inb(epp_p);
-#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
-       if (inb(str_p) & 0x01)
-           return 0;
-#endif
-    }
-    return 1;
-}
-
 static int ppa_in(int host_no, char *buffer, int len)
 {
     int r;
@@ -671,7 +446,7 @@ static int ppa_in(int host_no, char *buffer, int len)
     switch (ppa_hosts[host_no].mode) {
     case PPA_NIBBLE:
        /* 4 bit input, with a loop */
-       r = ppa_nibble_in(ppb + 1, buffer, len);
+       r = ppa_nibble_in(ppb, buffer, len);
        w_ctr(ppb, 0xc);
        break;
 
@@ -688,16 +463,17 @@ static int ppa_in(int host_no, char *buffer, int len)
     case PPA_EPP_8:
        epp_reset(ppb);
        w_ctr(ppb, 0x24);
-#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
-       r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+       if (!(((long) buffer | len) & 0x01))
+           insw(ppb + 4, buffer, len >> 1);
 #else
        if (!(((long) buffer | len) & 0x03))
            insl(ppb + 4, buffer, len >> 2);
+#endif
        else
            insb(ppb + 4, buffer, len);
        w_ctr(ppb, 0x2c);
        r = !(r_str(ppb) & 0x01);
-#endif
        w_ctr(ppb, 0x2c);
        ecp_sync(ppb);
        break;
@@ -885,7 +661,7 @@ static int ppa_completion(Scsi_Cmnd * cmd)
         * If we have been running for more than a full timer tick
         * then take a rest.
         */
-       if (time_after(jiffies,start_jiffies + 1))
+       if (time_after(jiffies, start_jiffies + 1))
            return 0;
 
        if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
@@ -1059,8 +835,7 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
            if ((r_str(ppb) & 0x08) == 0x00)
                retv--;
 
-           if (retv)
-           {
+           if (retv) {
                if ((jiffies - tmp->jstart) > (1 * HZ)) {
                    printk("ppa: Parallel port cable is unplugged!!\n");
                    ppa_fail(host_no, DID_BUS_BUSY);
index c58dd39b2abd6d376164876f7404aa33f7560124..58416c4c7a04b0009d5114059b9ac1831d6264f6 100644 (file)
@@ -2,15 +2,15 @@
  * the Iomega ZIP drive
  * 
  * (c) 1996     Grant R. Guenther  grant@torque.net
- *             David Campbell     campbell@torque.net
+ *              David Campbell     campbell@torque.net
  *
- *     All comments to David.
+ *      All comments to David.
  */
 
 #ifndef _PPA_H
 #define _PPA_H
 
-#define   PPA_VERSION   "2.01"
+#define   PPA_VERSION   "2.03 (for Linux 2.0.0)"
 
 /* 
  * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
  *
  * Corrected ppa.h for 2.1.x kernels (>=2.1.85)
  * Modified "Nat Semi Kludge" for extended chipsets
- *                                                     [1.41]
+ *                                                      [1.41]
  *
  * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7)
- *                                                     [1.42]
+ *                                                      [1.42]
  *
  * Development solely for 2.1.x kernels from now on!
- *                                                     [2.00]
+ *                                                      [2.00]
  *
  * Hack and slash at the init code (EPP device check routine)
  * Added INSANE option.
- *                                                     [2.01]
+ *                                                      [2.01]
  *
  * Patch applied to sync against the 2.1.x kernel code
  * Included qboot_zip.sh
- *                                                     [2.02]
+ *                                                      [2.02]
+ *
+ * Cleaned up the mess left by someone else trying to fix the
+ * asm section to keep egcc happy. The asm section no longer
+ * exists, the nibble code is *almost* as fast as the asm code
+ * providing it is compiled with egcc.
+ *
+ * Other clean ups include the follow changes:
+ *    CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
+ *    added CONFIG_SCSI_IZIP_SLOW_CTR option
+ *                                                      [2.03]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
@@ -80,7 +90,11 @@ static char *PPA_MODE_STRING[] =
     "PS/2",
     "EPP 8 bit",
     "EPP 16 bit",
+#ifdef CONFIG_SCSI_IZIP_EPP16
+    "EPP 16 bit",
+#else
     "EPP 32 bit",
+#endif
     "Unknown"};
 
 /* This is a global option */
@@ -98,23 +112,6 @@ int ppa_sg = SG_ALL;                /* enable/disable scatter-gather. */
 #define CONNECT_EPP_MAYBE 1
 #define CONNECT_NORMAL  0
 
-/* INSANE code */
-#define PPA_INSANE 0
-#if PPA_INSANE > 0
-#define r_dtr(x)        (unsigned char)inb_p((x))
-#define r_str(x)        (unsigned char)inb_p((x)+1)
-#define r_ctr(x)        (unsigned char)inb_p((x)+2)
-#define r_epp(x)        (unsigned char)inb_p((x)+4)
-#define r_fifo(x)       (unsigned char)inb_p((x)+0x400)
-#define r_ecr(x)        (unsigned char)inb_p((x)+0x402)
-
-#define w_dtr(x,y)      outb_p(y, (x))
-#define w_str(x,y)      outb_p(y, (x)+1)
-#define w_ctr(x,y)      outb_p(y, (x)+2)
-#define w_epp(x,y)      outb_p(y, (x)+4)
-#define w_fifo(x,y)     outb_p(y, (x)+0x400)
-#define w_ecr(x,y)      outb_p(y, (x)+0x402)
-#else /* PPA_INSANE */
 #define r_dtr(x)        (unsigned char)inb((x))
 #define r_str(x)        (unsigned char)inb((x)+1)
 #define r_ctr(x)        (unsigned char)inb((x)+2)
@@ -124,11 +121,15 @@ int ppa_sg = SG_ALL;              /* enable/disable scatter-gather. */
 
 #define w_dtr(x,y)      outb(y, (x))
 #define w_str(x,y)      outb(y, (x)+1)
-#define w_ctr(x,y)      outb(y, (x)+2)
 #define w_epp(x,y)      outb(y, (x)+4)
 #define w_fifo(x,y)     outb(y, (x)+0x400)
 #define w_ecr(x,y)      outb(y, (x)+0x402)
-#endif /* PPA_INSANE */
+
+#ifdef CONFIG_SCSI_IZIP_SLOW_CTR
+#define w_ctr(x,y)      outb_p(y, (x)+2)
+#else
+#define w_ctr(x,y)      outb(y, (x)+2)
+#endif
 
 static int ppa_engine(ppa_struct *, Scsi_Cmnd *);
 static int ppa_in(int, char *, int);
@@ -154,7 +155,7 @@ int ppa_biosparam(Disk *, kdev_t, int *);
 
 #define PPA {  proc_dir:                       &proc_scsi_ppa,         \
                proc_info:                      ppa_proc_info,          \
-               name:                           "Iomega parport ZIP drive",\
+               name:                           "Iomega VPI0 (ppa) interface",\
                detect:                         ppa_detect,             \
                release:                        ppa_release,            \
                command:                        ppa_command,            \
index 281c9ce289518f0e8ca0052a2f0558d883c33ee0..8536f69b433f6bb4efcb2609be36bbb82a51b032 100644 (file)
@@ -518,10 +518,10 @@ int scsi_debug_command(Scsi_Cmnd * SCpnt)
 static void scsi_debug_intr_handle(unsigned long indx)
 {
     Scsi_Cmnd * SCtmp;
-    int pending;
     void (*my_done)(Scsi_Cmnd *); 
-    unsigned long flags;
+#ifdef DEBUG
     int to;
+#endif
     
 #if 0
     del_timer(&timeout[indx]);
@@ -565,9 +565,11 @@ int scsi_debug_detect(Scsi_Host_Template * tpnt)
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
+#if 0
     int j;
     void (*my_done)(Scsi_Cmnd *);
     unsigned long flags;
+#endif
     
     DEB(printk("scsi_debug_abort\n"));
 #if 0
index 4ed9ba6343dec3d0394d3c0e41e0d902f037a22e..459a245d577bd58f7eeaa3aa47ef4ed5ef4a6834 100644 (file)
@@ -307,6 +307,13 @@ void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
     *size = y; 
     return;
 }
+
+#else
+
+void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
+{
+}
+
 #endif /* CONFIG_PROC_FS */
 
 /*
index c6d83f8a2c05cd6b08a6c60ccbf712bcd956ec6d..e73335a24566e7d26b67a321f6d5a043a9e8cee0 100644 (file)
@@ -72,9 +72,7 @@ EXPORT_SYMBOL(scsi_logging_level);
 
 EXPORT_SYMBOL(scsi_sleep);
 
-#if defined(CONFIG_PROC_FS)
 EXPORT_SYMBOL(proc_print_scsidevice);
-#endif
 /*
  * These are here only while I debug the rest of the scsi stuff.
  */
index aca163bb74ecc9d819d9ac90ecc55db2c392315a..b328b8f6bf301e81d2a3ffdc523827cdaca474f5 100644 (file)
@@ -909,8 +909,10 @@ void cleanup_module(void)
        {
                return;
        }
+#ifdef CONFIG_PROC_FS  
         if (proc_unregister(&proc_root, PROC_SOUND))
                printk(KERN_ERR "sound: unregistering /proc/sound failed\n");
+#endif         
        if (chrdev_registered)
                destroy_special_devices();
 
index 2597f1fb705638d7a04e2edd34ce54256e4d4217..cb062d5b10769fa2b48d9ef9d6ef9c19c50282d5 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/spinlock.h>
 
+/*
+ * We should make this work with a "stub-only" /proc,
+ * which would just not be able to be configured.
+ * Right now the /proc-fs support is too black and white,
+ * though, so just remind people that this should be
+ * fixed..
+ */
+#ifndef CONFIG_PROC_FS
+#error You really need /proc support for binfmt_misc. Please reconfigure!
+#endif
 
 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
 
@@ -67,9 +77,7 @@ static struct binfmt_entry *entries = NULL;
 static int free_id = 1;
 static int enabled = 1;
 
-#ifdef CONFIG_SMP
-static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
-#endif
+static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
 
 
 /*
@@ -458,8 +466,10 @@ static int entry_proc_setup(struct binfmt_entry *e)
 {
        if (!(e->proc_dir = create_proc_entry(e->proc_name,
                                S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
-               return -ENOMEM;
-
+       {
+               printk(KERN_WARNING "Unable to create /proc entry.\n");
+               return -ENOENT;
+       }
        e->proc_dir->data = (void *) (e->id);
        e->proc_dir->read_proc = proc_read_status;
        e->proc_dir->write_proc = proc_write_status;
@@ -486,7 +496,7 @@ static void bm_modcount(struct inode *inode, int fill)
 
 int __init init_misc_binfmt(void)
 {
-       int error = -ENOMEM;
+       int error = -ENOENT;
        struct proc_dir_entry *status = NULL, *reg;
 
        bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
index e103e05000074870f88da90f67c1e44514e0720a..bc67350cec9bc6dd333d741515af966d5fd059c5 100644 (file)
@@ -364,8 +364,8 @@ fat_read_super(struct super_block *sb, void *data, int silent)
                MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
                MSDOS_SB(sb)->fsinfo_offset =
                        CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
-               if (MSDOS_SB(sb)->fsinfo_offset + sizeof(MSDOS_SB(sb)->fsinfo_offset) >= sizeof(struct fat_boot_sector)) {
-                       printk("fat_read_super: Bad fsinfo_offset\n");
+               if (MSDOS_SB(sb)->fsinfo_offset + sizeof(MSDOS_SB(sb)->fsinfo_offset) > sb->s_blocksize) {
+                       printk("fat_read_super: Bad fsinfo_offset 0x%x\n", MSDOS_SB(sb)->fsinfo_offset);
                        fat_brelse(sb, bh);
                        goto out_invalid;
                }
index 516863b539a6910ab3846c6ad90bef263c0086a0..3b30a6a5a6d3d2688ea0055e751776d3e61f1398 100644 (file)
@@ -263,12 +263,8 @@ update_write_request(struct nfs_wreq *req, unsigned int first,
 static inline void
 free_write_request(struct nfs_wreq * req)
 {
-       if (!--req->wb_count) {
-               struct inode *inode = req->wb_inode;
-               remove_write_request(&NFS_WRITEBACK(inode), req);
+       if (!--req->wb_count)
                kfree(req);
-               nr_write_requests--;
-       }
 }
 
 /*
@@ -698,6 +694,8 @@ nfs_wback_result(struct rpc_task *task)
                clear_bit(PG_uptodate, &page->flags);
 
        __free_page(page);
+       remove_write_request(&NFS_WRITEBACK(inode), req);
+       nr_write_requests--;
        dput(req->wb_dentry);
 
        wake_up(&req->wb_wait);
index 80f718eea167af4dbb1a5aa1eea3c5dbfdbd57a0..fd7a5b227a636c5c268851634526a286d769fb19 100644 (file)
@@ -54,8 +54,6 @@ static int    nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
 
 static int     initialized = 0;
 
-#ifdef CONFIG_PROC_FS
-
 int exp_procfs_exports(char *buffer, char **start, off_t offset,
                              int length, int *eof, void *data);
 
@@ -70,7 +68,6 @@ void proc_export_init(void)
        nfs_export_ent->read_proc = exp_procfs_exports;
 }
 
-#endif
 
 /*
  * Initialize nfsd
@@ -79,16 +76,12 @@ static void
 nfsd_init(void)
 {
        nfsd_xdr_init();        /* XDR */
-#ifdef CONFIG_PROC_FS
        nfsd_stat_init();       /* Statistics */
-#endif
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
        nfsd_fh_init();         /* FH table */
-#ifdef CONFIG_PROC_FS
        proc_export_init();
-#endif
        initialized = 1;
 }
 
@@ -310,11 +303,9 @@ cleanup_module(void)
        nfsd_export_shutdown();
        nfsd_cache_shutdown();
        nfsd_fh_free();
-#ifdef CONFIG_PROC_FS
        remove_proc_entry("fs/nfs/exports", NULL);
        remove_proc_entry("fs/nfs", NULL);
        nfsd_stat_shutdown();
-#endif
        nfsd_lockd_shutdown();
 }
 #endif
index e05cd271d0424609902063d0ce2b84cc9cc4f583..ca5d7714454868c9a5703d3f9055a27ef35322b4 100644 (file)
@@ -27,7 +27,6 @@
 struct nfsd_stats      nfsdstats;
 struct svc_stat                nfsd_svcstats = { &nfsd_program, };
 
-#ifdef CONFIG_PROC_FS
 static int
 nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
                                int *eof, void *data)
@@ -90,4 +89,3 @@ nfsd_stat_shutdown(void)
 {
        svc_proc_unregister("nfsd");
 }
-#endif /* CONFIG_PROC_FS */
index a213e21e39b171454d0a4f4d4bca63cfb705b75d..38d8611771e79d66d81f3166ae7122f2df1e0e11 100644 (file)
@@ -993,7 +993,7 @@ out_nfserr:
 static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
 {
        if (s1 != s2) {
-               if ((unsigned long) s1 < (unsigned long) s2) {
+               if ((unsigned long) s1 > (unsigned long) s2) {
                        struct semaphore *tmp = s1;
                        s1 = s2;
                        s2 = tmp;
index bd753629980e81c5e489f6ec181650135652d235..8546f0bde632eb90aad8604f9d39780772e442c2 100644 (file)
@@ -3,7 +3,7 @@
 O_TARGET := ntfs.o
 O_OBJS   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
 M_OBJS   := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"980101\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"990102\"
 
 include $(TOPDIR)/Rules.make
 
index 8b53cb88392d5b4df59aeeefc67fba083c7367b5..3de728fb7dde1e967117f5692d69f1190aecd80c 100644 (file)
@@ -1,11 +1,12 @@
 /*
  *  attr.c
  *
- *  Copyright (C) 1996-1997 Martin von Löwis
+ *  Copyright (C) 1996-1998 Martin von Löwis
  *  Copyright (C) 1996-1997 Régis Duchesne
+ *  Copyright (C) 1998 Joseph Malicki
  */
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "attr.h"
 
@@ -81,7 +82,7 @@ ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr)
 
 /* Store in the inode readable information about a run */
 static void
-ntfs_insert_run(ntfs_attribute *attr,int cnum,int cluster,int len)
+ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len)
 {
        /* (re-)allocate space if necessary */
        if(attr->d.r.len % 8 == 0) {
@@ -107,11 +108,17 @@ int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
 {
        int error=0;
        ntfs_runlist *rl;
-       int rlen,cluster;
+       int rlen;
+       ntfs_cluster_t cluster;
        int clen;
        if(attr->compressed)return EOPNOTSUPP;
-       if(attr->resident)return EOPNOTSUPP;
        if(ino->record_count>1)return EOPNOTSUPP;
+       if(attr->resident) {
+               error = ntfs_make_attr_nonresident(ino,attr);
+               if(error)
+                       return error;
+       }
+
        rl=attr->d.r.runlist;
        rlen=attr->d.r.len-1;
        if(rlen>=0)
@@ -121,18 +128,20 @@ int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
                cluster=0;
        /* round up to multiple of cluster size */
        clen=(*len+ino->vol->clustersize-1)/ino->vol->clustersize;
+       if(clen==0)
+               return 0;
        /* FIXME: try to allocate smaller pieces */
        error=ntfs_allocate_clusters(ino->vol,&cluster,&clen,
                                     flags|ALLOC_REQUIRE_SIZE);
        if(error)return error;
-       attr->allocated+=clen;
+       attr->allocated += clen*ino->vol->clustersize;
        *len=clen*ino->vol->clustersize;
        /* contiguous chunk */
        if(rlen>=0 && cluster==rl[rlen].cluster+rl[rlen].len){
                rl[rlen].len+=clen;
                return 0;
        }
-       ntfs_insert_run(attr,rlen+1,cluster,*len);
+       ntfs_insert_run(attr,rlen+1,cluster,clen);
        return 0;
 }
 
@@ -158,6 +167,22 @@ ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
        return ntfs_readwrite_attr(ino,attr,0,&io);
 }
 
+int
+ntfs_attr_allnonresident(ntfs_inode *ino)
+{
+       int i, error=0;
+        ntfs_volume *vol = ino->vol;
+
+       for (i=0; !error && i<ino->attr_count; i++)
+       {
+               if (ino->attrs[i].type != vol->at_security_descriptor
+                   && ino->attrs[i].type != vol->at_data)
+                       continue;
+               error = ntfs_make_attr_nonresident (ino, ino->attrs+i);
+       }
+       return error;
+}
+
 /* Resize the attribute to a newsize */
 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
 {
@@ -175,7 +200,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
                return EOPNOTSUPP;
        if(attr->resident){
                void *v;
-               if(newsize>ino->vol->clustersize){
+               if(newsize>ino->vol->mft_recordsize){
                        error=ntfs_make_attr_nonresident(ino,attr);
                        if(error)return error;
                        return ntfs_resize_attr(ino,attr,newsize);
@@ -185,8 +210,10 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
                        attr->d.data=ntfs_malloc(newsize);
                        if(!attr->d.data)
                                return ENOMEM;
-                       ntfs_bzero(attr->d.data+oldsize,newsize);
-                       ntfs_memcpy(attr->d.data,v,min(newsize,oldsize));
+                       if(newsize>oldsize)
+                               ntfs_bzero((char*)attr->d.data+oldsize,
+                                          newsize-oldsize);
+                       ntfs_memcpy((char*)attr->d.data,v,min(newsize,oldsize));
                }else
                        attr->d.data=0;
                ntfs_free(v);
@@ -199,7 +226,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
                for(i=0,count=0;i<attr->d.r.len;i++){
                        if((count+rl[i].len)*clustersize>newsize)
                                break;
-                       count+=rl[i].len;
+                       count+=(int)rl[i].len;
                }
                newlen=i+1;
                /* free unused clusters in current run, unless sparse */
@@ -208,7 +235,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
                        int rounded=newsize-count*clustersize;
                        rounded=(rounded+clustersize-1)/clustersize;
                        error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded,
-                                                      rl[i].len-rounded);
+                                                      (int)rl[i].len-rounded);
                        if(error)
                                return error; /* FIXME: incomplete operation */
                        rl[i].len=rounded;
@@ -217,7 +244,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
                /* free all other runs */
                for(i++;i<attr->d.r.len;i++)
                        if(rl[i].cluster!=-1){
-                               error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,rl[i].len);
+                               error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,(int)rl[i].len);
                                if(error)
                                        return error; /* FIXME: incomplete operation */
                        }
@@ -232,7 +259,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
        /* fill in new sizes */
        attr->allocated = newcount*clustersize;
        attr->size = newsize;
-       attr->initialized = newsize;
+       /* attr->initialized does not change. */
        if(!newsize)
                error=ntfs_make_attr_resident(ino,attr);
        return error;
@@ -296,7 +323,8 @@ ntfs_process_runs(ntfs_inode *ino,ntfs_attribute* attr,unsigned char *data)
 {
        int startvcn,endvcn;
        int vcn,cnum;
-       int cluster,len,ctype;
+       ntfs_cluster_t cluster;
+       int len,ctype;
        startvcn = NTFS_GETU64(data+0x10);
        endvcn = NTFS_GETU64(data+0x18);
 
@@ -383,13 +411,29 @@ int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
        return 0;
 }
 
+int
+ntfs_read_zero(ntfs_io *dest,int size)
+{
+       char *sparse=ntfs_calloc(512);
+       if(!sparse)
+               return ENOMEM;
+       while(size){
+               int i=min(size,512);
+               dest->fn_put(dest,sparse,i);
+               size-=i;
+       }
+       ntfs_free(sparse);
+       return 0;
+}
+
 /* process compressed attributes */
 int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
        ntfs_io *dest)
 {
        int error=0;
        int clustersize,l;
-       int s_vcn,rnum,vcn,cluster,len,chunk,got,cl1,l1,offs1,copied;
+       int s_vcn,rnum,vcn,len,chunk,got,l1,offs1,copied;
+       ntfs_cluster_t cluster,cl1;
        char *comp=0,*comp1;
        char *decomp=0;
        ntfs_io io;
@@ -426,18 +470,13 @@ int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
                chunk=0;
                if(cluster==-1){
                        /* sparse cluster */
-                       char *sparse=ntfs_calloc(512);
                        int l1;
-                       if(!sparse)return ENOMEM;
                        if((len-(s_vcn-vcn)) & 15)
                                ntfs_error("unexpected sparse chunk size");
                        l1=chunk = min((vcn+len)*clustersize-offset,l);
-                       while(l1){
-                               int i=min(l1,512);
-                               dest->fn_put(dest,sparse,i);
-                               l1-=i;
-                       }
-                       ntfs_free(sparse);
+                       error = ntfs_read_zero(dest,l1);
+                       if(error)
+                               goto out;
                }else if(dest->do_read){
                        if(!comp){
                                comp=ntfs_malloc(16*clustersize);
index 08156c4f245a63c95f0cc1f713c07b92d4e2e113..6ba6f5b27dbd5d81b1376c4a5a6986d3efb7f3d1 100644 (file)
@@ -15,3 +15,6 @@ int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
   ntfs_io *dest);
 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
   int dsize, ntfs_attribute **rattr);
+int ntfs_read_zero(ntfs_io *dest,int size);
+int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr);
+int ntfs_attr_allnonresident(ntfs_inode *ino);
index ee995c046f7b2e06513175ec4045f0ea78506891..ff18aa15c5faca3a8b20f88872052c4f08e31915 100644 (file)
@@ -4,9 +4,10 @@
  *  Copyright (C) 1995-1997 Martin von Löwis
  */
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "dir.h"
+#include "macros.h"
 
 #include <linux/errno.h>
 #include "super.h"
@@ -26,27 +27,27 @@ int ntfs_check_index_record(ntfs_inode *ino, char *record)
                                 ino->u.index.recordsize);
 }
 
-static inline int ntfs_is_top(long long stack)
+static inline int ntfs_is_top(ntfs_u64 stack)
 {
        return stack==14;
 }
 
-static long long ntfs_pop(long long *stack)
+static int ntfs_pop(ntfs_u64 *stack)
 {
        static int width[16]={1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
        int res=-1;
        switch(width[*stack & 15])
        {
-       case 1:res=(*stack&15)>>1;
+       case 1:res=(int)((*stack&15)>>1);
                *stack>>=4;
                break;
-       case 2:res=((*stack&63)>>2)+7;
+       case 2:res=(int)(((*stack&63)>>2)+7);
                *stack>>=6;
                break;
-       case 3:res=((*stack & 255)>>3)+23;
+       case 3:res=(int)(((*stack & 255)>>3)+23);
                *stack>>=8;
                break;
-       case 4:res=((*stack & 1023)>>4)+55;
+       case 4:res=(int)(((*stack & 1023)>>4)+55);
                *stack>>=10;
                break;
        default:ntfs_error("Unknown encoding\n");
@@ -59,18 +60,18 @@ static inline unsigned int ntfs_top(void)
        return 14;
 }
 
-static long long ntfs_push(long long stack,int i)
+static ntfs_u64 ntfs_push(ntfs_u64 stack,int i)
 {
        if(i<7)return (stack<<4)|(i<<1);
        if(i<23)return (stack<<6)|((i-7)<<2)|1;
        if(i<55)return (stack<<8)|((i-23)<<3)|3;
        if(i<120)return (stack<<10)|((i-55)<<4)|7;
        ntfs_error("Too many entries\n");
-       return -1;
+       return 0xFFFFFFFFFFFFFFFF;
 }
 
 #if 0
-static void ntfs_display_stack(long long stack)
+static void ntfs_display_stack(ntfs_u64 stack)
 {
        while(!ntfs_is_top(stack))
        {
@@ -162,35 +163,30 @@ static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
        if(walk->newblock * vol->clustersize >= size){
                /* build index record */
                int s1=walk->dir->u.index.recordsize;
+               int nr_fix = s1/vol->blocksize+1;
+               int hsize;
                char *record=ntfs_malloc(s1);
-               int newlen;
                ntfs_bzero(record,s1);
                /* magic */
                ntfs_memcpy(record,"INDX",4);
                /* offset to fixups */
                NTFS_PUTU16(record+4,0x28);
                /* number of fixups */
-               NTFS_PUTU16(record+6,s1/vol->blocksize+1);
+               NTFS_PUTU16(record+6,nr_fix);
                /* FIXME: log file number */
                /* VCN of buffer */
                NTFS_PUTU64(record+0x10,walk->newblock);
-               /* header size. FIXME */
-               NTFS_PUTU16(record+0x18,28);
+               /* header size. */
+               hsize = 0x10+2*nr_fix;
+               hsize = (hsize+7) & ~7; /* Align. */
+               NTFS_PUTU16(record+0x18, hsize);
                /* total size of record */
                NTFS_PUTU32(record+0x20,s1-0x18);
+               /* Writing the data will extend the attribute. */
                io.param=record;
-               newlen=walk->dir->u.index.recordsize;
-               /* allocate contiguous index record */
-               error=ntfs_extend_attr(walk->dir,allocation,&newlen,
-                                      ALLOC_REQUIRE_SIZE);
-               if(error){
-                       /* FIXME: try smaller allocations */
-                       ntfs_free(record);
-                       return ENOSPC;
-               }
                io.size=s1;
-               error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30,
-                                     size,&io);
+               io.do_read=0;
+               error=ntfs_readwrite_attr(walk->dir, allocation, size, &io);
                if(error || io.size!=s1){
                        ntfs_free(record);
                        return error?error:EIO;
@@ -201,29 +197,38 @@ static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
        return 0;
 }
 
+/* Write an index block (root or allocation) back to storage.
+   used is the total number of bytes in buf, including all headers. */
+
 static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block,
-       int used)
+                               int used)
 {
        ntfs_io io;
        int error;
+       ntfs_attribute *a;
+       ntfs_volume *vol = walk->dir->vol;
+       
        io.fn_put=0;
        io.fn_get=ntfs_get;
        io.param=buf;
-       if(walk->block==-1){
+       if(block==-1){
                NTFS_PUTU16(buf+0x14,used-0x10);
                /* 0x18 is a copy thereof */
                NTFS_PUTU16(buf+0x18,used-0x10);
                io.size=used;
-               error=ntfs_write_attr(walk->dir,walk->dir->vol->at_index_root,
+               error=ntfs_write_attr(walk->dir,vol->at_index_root,
                                      I30,0,&io);
                if(error)return error;
                if(io.size!=used)return EIO;
+               /* shrink if necessary */
+               a = ntfs_find_attr(walk->dir, vol->at_index_root, I30);
+               ntfs_resize_attr(walk->dir, a, used);
        }else{
-               NTFS_PUTU16(buf+0x1C,used-0x20);
-               ntfs_insert_fixups(buf,walk->dir->vol->blocksize);
+               NTFS_PUTU16(buf+0x1C,used-0x18);
+               ntfs_insert_fixups(buf,vol->blocksize);
                io.size=walk->dir->u.index.recordsize;
-               error=ntfs_write_attr(walk->dir,walk->dir->vol->at_index_allocation,I30,
-                                     walk->block*walk->dir->vol->clustersize,
+               error=ntfs_write_attr(walk->dir,vol->at_index_allocation,I30,
+                                     block*vol->clustersize,
                                      &io);
                if(error)return error;
                if(io.size!=walk->dir->u.index.recordsize)
@@ -240,13 +245,20 @@ static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
        int error,othersize,mlen;
        ntfs_io io;
        ntfs_volume *vol=walk->dir->vol;
+       int oldblock;
+
        error=ntfs_allocate_index_block(walk);
        if(error)
                return error;
-       for(entry=prev=start+NTFS_GETU16(start+0x18)+0x18;
-           entry-start<usize/2;
-           entry+=NTFS_GETU16(entry+8))
+       /* This should not happen */
+       if(walk->block == -1){
+               ntfs_error("Trying to split root");
+               return EOPNOTSUPP;
+       }
+       entry = start+NTFS_GETU16(start+0x18)+0x18; 
+       for(prev=entry; entry-start<usize/2; entry += NTFS_GETU16(entry+8))
                prev=entry;
+
        newbuf=ntfs_malloc(vol->index_recordsize);
        if(!newbuf)
                return ENOMEM;
@@ -266,11 +278,19 @@ static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
        /* copy everything from entry to new block */
        othersize=usize-(entry-start);
        ntfs_memcpy(newbuf+NTFS_GETU16(newbuf+0x18)+0x18,entry,othersize);
-       error=ntfs_index_writeback(walk,newbuf,walk->newblock,othersize);
+       /* Copy flags. */
+       NTFS_PUTU32(newbuf+0x24, NTFS_GETU32(start+0x24));
+       error=ntfs_index_writeback(walk,newbuf,walk->newblock,
+                                  othersize+NTFS_GETU16(newbuf+0x18)+0x18);
        if(error)goto out;
 
        /* move prev to walk */
        mlen=NTFS_GETU16(prev+0x8);
+       /* Remember old child node. */
+       if(ntfs_entry_has_subnodes(prev))
+               oldblock = NTFS_GETU32(prev+mlen-8);
+       else
+               oldblock = -1;
        /* allow for pointer to subnode */
        middle=ntfs_malloc(ntfs_entry_has_subnodes(prev)?mlen:mlen+8);
        if(!middle){
@@ -286,8 +306,21 @@ static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
                ntfs_error("entry not reset");
        walk->new_entry=middle;
        walk->u.flags|=ITERATE_SPLIT_DONE;
+       /* Terminate old block. */
+       othersize = usize-(prev-start);
+       NTFS_PUTU64(prev, 0);
+       if(oldblock==-1){
+               NTFS_PUTU32(prev+8, 0x10);
+               NTFS_PUTU32(prev+0xC, 2);
+               othersize += 0x10;
+       }else{
+               NTFS_PUTU32(prev+8, 0x18);
+               NTFS_PUTU32(prev+0xC, 3);
+               NTFS_PUTU64(prev+0x10, oldblock);
+               othersize += 0x18;
+       }
        /* write back original block */
-       error=ntfs_index_writeback(walk,start,walk->block,usize-(prev-start));
+       error=ntfs_index_writeback(walk,start,walk->block,othersize);
  out:
        if(newbuf)ntfs_free(newbuf);
        if(middle)ntfs_free(middle);
@@ -300,12 +333,11 @@ static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
        int do_split=0;
        offset=entry-start;
        if(walk->block==-1){ /*index root */
-               /* FIXME: adjust to maximum allowed index root value */
                blocksize=walk->dir->vol->mft_recordsize;
                usedsize=NTFS_GETU16(start+0x14)+0x10;
        }else{
                blocksize=walk->dir->u.index.recordsize;
-               usedsize=NTFS_GETU16(start+0x1C)+0x20;
+               usedsize=NTFS_GETU16(start+0x1C)+0x18;
        }
        if(usedsize+walk->new_entry_size > blocksize){
                char* s1=ntfs_malloc(blocksize+walk->new_entry_size);
@@ -321,7 +353,6 @@ static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
        usedsize+=walk->new_entry_size;
        ntfs_free(walk->new_entry);
        walk->new_entry=0;
-       /*FIXME: split root */
        if(do_split){
                error=ntfs_split_record(walk,start,blocksize,usedsize);
                ntfs_free(start);
@@ -330,6 +361,81 @@ static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
        return 0;
 }
 
+/* Try to split INDEX_ROOT attributes. Return E2BIG if nothing changed. */
+
+int
+ntfs_split_indexroot(ntfs_inode *ino)
+{
+       ntfs_attribute *ra;
+       ntfs_u8 *root=0, *index=0;
+       ntfs_io io;
+       int error, off, i, bsize, isize;
+       ntfs_iterate_s walk;
+
+       ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
+       if(!ra)
+               return E2BIG;
+       bsize = ino->vol->mft_recordsize;
+       root = ntfs_malloc(bsize);
+       if(!root)
+               return E2BIG;
+       io.fn_put = ntfs_put;
+       io.param = root;
+       io.size = bsize;
+       error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io);
+       if(error)
+               goto out;
+       off = 0x20;
+       /* Count number of entries. */
+       for(i = 0; ntfs_entry_is_used(root+off); i++)
+               off += NTFS_GETU16(root+off+8);
+       if(i<=2){
+               /* We don't split small index roots. */
+               error = E2BIG;
+               goto out;
+       }
+       index = ntfs_malloc(ino->vol->index_recordsize);
+       if(!index)
+               goto out;
+       walk.dir = ino;
+       walk.block = -1;
+       walk.result = walk.new_entry = 0;
+       walk.name = 0;
+       error = ntfs_allocate_index_block(&walk);
+       if(error)
+               goto out;
+
+       /* Write old root to new index block. */
+       io.param = index;
+       io.size = ino->vol->index_recordsize;
+       error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30,
+                              walk.newblock*ino->vol->clustersize, &io);
+       if(error)
+               goto out;
+       isize = NTFS_GETU16(root+0x18) - 0x10;
+       ntfs_memcpy(index+NTFS_GETU16(index+0x18)+0x18, root+0x20, isize);
+       /* Copy flags. */
+       NTFS_PUTU32(index+0x24, NTFS_GETU32(root+0x1C));
+
+       error = ntfs_index_writeback(&walk, index, walk.newblock, 
+                                    isize+NTFS_GETU16(index+0x18)+0x18);
+       if(error)
+               goto out;
+
+       /* Mark root as split. */
+       NTFS_PUTU32(root+0x1C, 1);
+       /* Truncate index root. */
+       NTFS_PUTU64(root+0x20, 0);
+       NTFS_PUTU32(root+0x28, 0x18);
+       NTFS_PUTU32(root+0x2C, 3);
+       NTFS_PUTU64(root+0x30, walk.newblock);
+       error = ntfs_index_writeback(&walk,root,-1,0x38);
+ out:
+       ntfs_free(root);
+       ntfs_free(index);
+       return error;
+}
+
 /* The entry has been found. Copy the result in the caller's buffer */
 static int ntfs_copyresult(char *dest,char *source)
 {
@@ -419,9 +525,9 @@ static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry)
        error=ntfs_getdir_record(walk,nextblock);
        if(!error && walk->type==DIR_INSERT && 
           (walk->u.flags & ITERATE_SPLIT_DONE)){
-               /* split has occurred. adjust entry, insert new_entry */
+               /* Split has occurred. Adjust entry, insert new_entry. */
                NTFS_PUTU32(entry+length-8,walk->newblock);
-               /* reset flags, as the current block might be split again */
+               /* Reset flags, as the current block might be split again. */
                walk->u.flags &= ~ITERATE_SPLIT_DONE;
                error=ntfs_dir_insert(walk,start,entry);
        }
@@ -637,6 +743,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                ntfs_error("Inode %d has no volume\n",ino->i_number);
                return EINVAL;
        }
+       ntfs_debug(DEBUG_DIR3,"unsorted 1\n");
        /* are we still in the index root */
        if(*p_high==0){
                buf=ntfs_malloc(length=vol->mft_recordsize);
@@ -651,6 +758,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                ino->u.index.recordsize = NTFS_GETU32(buf+0x8);
                ino->u.index.clusters_per_record = NTFS_GETU32(buf+0xC);
                entry=buf+0x20;
+               ntfs_debug(DEBUG_DIR3,"unsorted 2\n");
        }else{ /* we are in an index record */
                length=ino->u.index.recordsize;
                buf=ntfs_malloc(length);
@@ -673,14 +781,17 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                        return ENOTDIR;
                }
                entry=buf+NTFS_GETU16(buf+0x18)+0x18;
+               ntfs_debug(DEBUG_DIR3,"unsorted 3\n");
        }
 
        /* process the entries */
        start=*p_low;
        while(ntfs_entry_is_used(entry)){
+               ntfs_debug(DEBUG_DIR3,"unsorted 4\n");
                if(start)
                        start--; /* skip entries that were already processed */
                else{
+                       ntfs_debug(DEBUG_DIR3,"unsorted 5\n");
                        if((error=cb(entry,param)))
                                /* the entry could not be processed */
                                break;
@@ -689,9 +800,11 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                entry+=NTFS_GETU16(entry+8);
        }
 
+       ntfs_debug(DEBUG_DIR3,"unsorted 6\n");
        /* caller did not process all entries */
        if(error){
                ntfs_free(buf);
+               ntfs_debug(DEBUG_DIR3,"unsorted 7\n");
                return error;
        }
 
@@ -704,6 +817,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                /* directory does not have index allocation */
                *p_high=0xFFFFFFFF;
                *p_low=0;
+               ntfs_debug(DEBUG_DIR3,"unsorted 8\n");
                return 0;
        }
        buf=ntfs_malloc(length=attr->size);
@@ -713,6 +827,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
        if(!error && io.size!=length)error=EIO;
        if(error){
                ntfs_free(buf);
+               ntfs_debug(DEBUG_DIR3,"unsorted 9\n");
                return EIO;
        }
        attr=ntfs_find_attr(ino,vol->at_index_allocation,I30);
@@ -721,6 +836,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                        /* no more index records */
                        *p_high=0xFFFFFFFF;
                        ntfs_free(buf);
+                       ntfs_debug(DEBUG_DIR3,"unsorted 10\n");
                        return 0;
                }
                *p_high+=ino->u.index.clusters_per_record;
@@ -731,6 +847,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                if(buf[byte] & bit)
                        break;
        }
+       ntfs_debug(DEBUG_DIR3,"unsorted 11\n");
        ntfs_free(buf);
        return 0;
 }
@@ -801,6 +918,62 @@ int ntfs_dir_add1(ntfs_inode *dir,const char* name,int namelen,ntfs_inode *ino)
 }
 #endif
 
+/* Fills out and creates an INDEX_ROOT attribute. */
+
+static int
+add_index_root (ntfs_inode *ino, int type)
+{
+       ntfs_attribute *da;
+       ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry */
+       char name[10];
+
+       NTFS_PUTU32(data, type);
+       /* ??? */
+       NTFS_PUTU32(data+4, 1);
+       NTFS_PUTU32(data+8, ino->vol->index_recordsize);
+       NTFS_PUTU32(data+0xC, ino->vol->index_clusters_per_record);
+       /* ??? */
+       NTFS_PUTU32(data+0x10, 0x10);
+       /* Size of entries, including header. */
+       NTFS_PUTU32(data+0x14, 0x20);
+       NTFS_PUTU32(data+0x18, 0x20);
+       /* No index allocation, yet. */
+       NTFS_PUTU32(data+0x1C, 0);
+       /* add last entry. */
+       /* indexed MFT record. */
+       NTFS_PUTU64(data+0x20, 0);
+       /* size of entry */
+       NTFS_PUTU32(data+0x28, 0x10);
+       /* flags: last entry, no child nodes. */
+       NTFS_PUTU32(data+0x2C, 2);
+       /* compute name */
+       ntfs_indexname(name, type);
+       return ntfs_create_attr(ino, ino->vol->at_index_root, name,
+                               data, sizeof(data), &da);
+}
+
+int
+ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *result)
+{
+       int error;
+       error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
+       if(error)
+               goto out;
+       error = add_index_root(result, 0x30);
+       if (error)
+               goto out;
+       /* Set directory bit */
+       result->attr[0x16] |= 2;
+       error = ntfs_update_inode (dir);
+       if (error)
+               goto out;
+       error = ntfs_update_inode (result);
+       if (error)
+               goto out;
+ out:
+       return error;
+}
+
 /*
  * Local variables:
  * c-file-style: "linux"
index 2ce409dc246478134401561aef20568e95e349c4..9c86e60638d0a0567c59a5ae349e4d9c3ec21cda 100644 (file)
@@ -18,7 +18,7 @@ typedef struct ntfs_iterate_s{
        enum ntfs_iterate_e type;
        ntfs_inode *dir;
        union{
-               long long pos;
+               ntfs_u64 pos;
                int flags;
        }u;
        char *result;      /* pointer to entry if found */
@@ -37,3 +37,5 @@ int ntfs_getdir_byname(ntfs_iterate_s *walk);
 int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name);
 int ntfs_check_index_record(ntfs_inode *ino, char *record);
 int ntfs_getdir_byposition(ntfs_iterate_s *walk);
+int ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *ino);
+int ntfs_split_indexroot(ntfs_inode *ino);
index bb489912b4396bdf8fbe5fde3e59fccfa4f452fd..016f45a063bd7dc5453435a5b5e36a19aa8a5790 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/config.h>
 #endif
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "util.h"
 #include "inode.h"
@@ -29,6 +29,9 @@
 #include <linux/locks.h>
 #include <linux/init.h>
 
+/* Forward declarations */
+static struct inode_operations ntfs_dir_inode_operations;
+
 #define ITEM_SIZE 2040
 
 /* io functions to user space */
@@ -39,10 +42,19 @@ static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len)
 }
 
 #ifdef CONFIG_NTFS_RW
-static void ntfs_getuser(void *dest,ntfs_io *src,ntfs_size_t len)
+struct ntfs_getuser_update_vm_s{
+       const char *user;
+       struct inode *ino;
+       loff_t off;
+};
+
+static void ntfs_getuser_update_vm (void *dest, ntfs_io *src, ntfs_size_t len)
 {
-       copy_from_user(dest,src->param,len);
-       src->param+=len;
+       struct ntfs_getuser_update_vm_s *p = src->param;
+       copy_from_user (dest, p->user, len);
+       update_vm_cache (p->ino, p->off, dest, len);
+       p->user += len;
+       p->off += len;
 }
 #endif
 
@@ -77,31 +89,42 @@ ntfs_read(struct file * filp, char *buf, size_t count, loff_t *off)
 static ssize_t
 ntfs_write(struct file *filp,const char* buf,size_t count,loff_t *pos)
 {
-       struct super_block* sb;
        int ret;
        ntfs_io io;
-       ntfs_inode *ino=NTFS_LINO2NINO(filp->f_dentry->d_inode);
+       struct inode *inode = filp->f_dentry->d_inode;
+       ntfs_inode *ino = NTFS_LINO2NINO(inode);
+       struct ntfs_getuser_update_vm_s param;
 
-       if(!ino)return -EINVAL;
-       ntfs_debug(DEBUG_OTHER, "ntfs_write %x,%x,%x ->",
-              (unsigned)ino->i_number,(unsigned)*pos,(unsigned)count);
-       sb = filp->f_dentry->d_inode->i_sb;
+       if (!ino)
+               return -EINVAL;
+       ntfs_debug (DEBUG_LINUX, "ntfs_write %x,%x,%x ->\n",
+              (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count);
        /* Allows to lock fs ro at any time */
-       if(sb->s_flags & MS_RDONLY)
+       if (inode->i_sb->s_flags & MS_RDONLY)
                return -ENOSPC;
-       if(!ntfs_find_attr(ino,ino->vol->at_data,NULL))
+       if (!ntfs_find_attr(ino,ino->vol->at_data,NULL))
                return -EINVAL;
 
-       io.fn_put=0;
-       io.fn_get=ntfs_getuser;
-       io.param=(void*)buf; /* to get rid of the const */
-       io.size=count;
-       ret = ntfs_write_attr(ino,ino->vol->at_data,NULL,*pos,&io);
-       ntfs_debug(DEBUG_OTHER, "%x\n",ret);
-       if(ret<0)return -EINVAL;
+       /* Evaluating O_APPEND is the file system's job... */
+       if (filp->f_flags & O_APPEND)
+               *pos = inode->i_size;
+       param.user = buf;
+       param.ino = inode;
+       param.off = *pos;
+       io.fn_put = 0;
+       io.fn_get = ntfs_getuser_update_vm;
+       io.param = &param;
+       io.size = count;
+       ret = ntfs_write_attr (ino, ino->vol->at_data, NULL, *pos, &io);
+       ntfs_debug (DEBUG_LINUX, "write -> %x\n", ret);
+       if(ret<0)
+               return -EINVAL;
 
-       *pos+=ret;
-       return ret;
+       *pos += io.size;
+       if (*pos > inode->i_size)
+               inode->i_size = *pos;
+       mark_inode_dirty (filp->f_dentry->d_inode);
+       return io.size;
 }
 #endif
 
@@ -119,10 +142,13 @@ static int ntfs_printcb(ntfs_u8 *entry,void *param)
 {
        struct ntfs_filldir* nf=param;
        int flags=NTFS_GETU8(entry+0x51);
-       int show_hidden=0,to_lower=0;
+       int show_hidden=0;
        int length=NTFS_GETU8(entry+0x50);
        int inum=NTFS_GETU32(entry);
-       int i,error;
+       int error;
+#ifdef NTFS_NGT_NT_DOES_LOWER
+       int i,to_lower=0;
+#endif
        switch(nf->type){
        case ngt_dos:
                /* Don't display long names */
@@ -133,7 +159,9 @@ static int ntfs_printcb(ntfs_u8 *entry,void *param)
                /* Don't display short-only names */
                switch(flags&3){
                case 2: return 0;
+#ifdef NTFS_NGT_NT_DOES_LOWER
                case 3: to_lower=1;
+#endif
                }
                break;
        case ngt_posix:
@@ -156,6 +184,7 @@ static int ntfs_printcb(ntfs_u8 *entry,void *param)
        /* Do not return ".", as this is faked */
        if(length==1 && *nf->name=='.')
                return 0;
+#ifdef NTFS_NGT_NT_DOES_LOWER
        if(to_lower)
                for(i=0;i<nf->namelen;i++)
                        /* This supports ASCII only. Since only DOS-only
@@ -163,6 +192,7 @@ static int ntfs_printcb(ntfs_u8 *entry,void *param)
                           to ASCII, this should be correct */
                        if(nf->name[i]>='A' && nf->name[i]<='Z')
                                nf->name[i]+='a'-'A';
+#endif
        nf->name[nf->namelen]=0;
        ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen);
        /* filldir expects an off_t rather than an loff_t.
@@ -349,7 +379,7 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
        char *item=0;
        ntfs_iterate_s walk;
        int error;
-       ntfs_debug(DEBUG_OTHER, "Looking up %s in %x\n",d->d_name.name,
+       ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name,
                   (unsigned)dir->i_ino);
        /* convert to wide string */
        error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
@@ -369,10 +399,11 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
        d_add(d,res);
        ntfs_free(item);
        ntfs_free(walk.name);
-       return res?0:-ENOENT;
+       /* Always return success, the dcache will handle negative entries. */
+       return 0;
 }
 
-struct file_operations ntfs_file_operations_nommap = {
+static struct file_operations ntfs_file_operations_nommap = {
        NULL, /* lseek */
        ntfs_read,
 #ifdef CONFIG_NTFS_RW
@@ -394,7 +425,7 @@ struct file_operations ntfs_file_operations_nommap = {
        NULL, /* lock */
 };
 
-struct inode_operations ntfs_inode_operations_nobmap = {
+static struct inode_operations ntfs_inode_operations_nobmap = {
        &ntfs_file_operations_nommap,
        NULL, /* create */
        NULL, /* lookup */
@@ -445,7 +476,7 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
        }
        r->u.generic_ip=ino;
 #endif
-       error=ntfs_alloc_inode(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name,
+       error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name,
                               d->d_name.len);
        if(error)goto fail;
        error=ntfs_update_inode(ino);
@@ -483,6 +514,65 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
        if(r)iput(r);
        return -error;
 }
+
+static int
+_linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
+{
+       int error;
+       struct inode *r = 0;
+       ntfs_volume *vol;
+       ntfs_inode *ino;
+       ntfs_attribute *si;
+
+       ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n",d->d_name.name, dir->i_ino);
+       error = ENAMETOOLONG;
+       if (d->d_name.len > /* FIXME */255)
+               goto out;
+
+       error = EIO;
+       r = get_empty_inode();
+       if (!r)
+               goto out;
+       
+       vol = NTFS_INO2VOL(dir);
+#ifdef NTFS_IN_LINUX_KERNEL
+       ino = NTFS_LINO2NINO(r);
+#else
+       ino = ntfs_malloc(sizeof(ntfs_inode));
+       error = ENOMEM;
+       if(!ino)
+               goto out;
+       r->u.generic_ip = ino;
+#endif
+       error = ntfs_mkdir(NTFS_LINO2NINO(dir), 
+                          d->d_name.name, d->d_name.len, ino);
+       if(error)
+               goto out;
+       r->i_uid = vol->uid;
+       r->i_gid = vol->gid;
+       r->i_nlink = 1;
+       r->i_sb = dir->i_sb;
+       si = ntfs_find_attr(ino,vol->at_standard_information,NULL);
+       if(si){
+               char *attr = si->d.data;
+               r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18));
+               r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
+               r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+8));
+       }
+       /* It's a directory */
+       r->i_op = &ntfs_dir_inode_operations;
+       r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+#ifdef CONFIG_NTFS_RW
+       r->i_mode|=S_IWUGO;
+#endif
+       r->i_mode &= ~vol->umask;       
+       
+       d_instantiate(d, r);
+       error = 0;
+ out:
+       ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error);
+       return -error;
+}
 #endif
 
 static int 
@@ -491,10 +581,12 @@ ntfs_bmap(struct inode *ino,int block)
        int ret=ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino),block);
        ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n",
               ino->i_ino,block,ret);
+       ntfs_error("bmap of %lx,block %x is %x\n", ino->i_ino,block,ret);
+       ntfs_error("super %x\n", ino->i_sb->s_blocksize); 
        return (ret==-1) ? 0:ret;
 }
 
-struct file_operations ntfs_file_operations = {
+static struct file_operations ntfs_file_operations = {
        NULL, /* lseek */
        ntfs_read,
 #ifdef CONFIG_NTFS_RW
@@ -516,7 +608,7 @@ struct file_operations ntfs_file_operations = {
        NULL, /* lock */
 };
 
-struct inode_operations ntfs_inode_operations = {
+static struct inode_operations ntfs_inode_operations = {
        &ntfs_file_operations,
        NULL, /* create */
        NULL, /* lookup */
@@ -539,7 +631,7 @@ struct inode_operations ntfs_inode_operations = {
        NULL, /* revalidate */
 };
 
-struct file_operations ntfs_dir_operations = {
+static struct file_operations ntfs_dir_operations = {
        NULL, /* lseek */
        NULL, /* read */
        NULL, /* write */
@@ -557,7 +649,7 @@ struct file_operations ntfs_dir_operations = {
        NULL, /* lock */
 };
 
-struct inode_operations ntfs_dir_inode_operations = {
+static struct inode_operations ntfs_dir_inode_operations = {
        &ntfs_dir_operations,
 #ifdef CONFIG_NTFS_RW
        ntfs_create, /* create */
@@ -568,7 +660,11 @@ struct inode_operations ntfs_dir_inode_operations = {
        NULL, /* link */
        NULL, /* unlink */
        NULL, /* symlink */
-       NULL, /* mkdir */
+#ifdef CONFIG_NTFS_RW
+       _linux_ntfs_mkdir, /* mkdir */
+#else
+       NULL,
+#endif
        NULL, /* rmdir */
        NULL, /* mknod */
        NULL, /* rename */
@@ -669,9 +765,14 @@ static void ntfs_read_inode(struct inode* inode)
        inode->i_mode &= ~vol->umask;
 }
 
-static void ntfs_put_inode(struct inode *ino)
+#ifdef CONFIG_NTFS_RW
+static void 
+ntfs_write_inode (struct inode *ino)
 {
+       ntfs_debug (DEBUG_LINUX, "ntfs:write inode %x\n", ino->i_ino);
+       ntfs_update_inode (NTFS_LINO2NINO (ino));
 }
+#endif
 
 static void _ntfs_clear_inode(struct inode *ino)
 {
@@ -747,10 +848,14 @@ static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
 }
 
 /* Define the super block operation that are implemented */
-struct super_operations ntfs_super_operations = {
+static struct super_operations ntfs_super_operations = {
        ntfs_read_inode,
-       NULL, /* write_inode */
-       ntfs_put_inode,
+#ifdef CONFIG_NTFS_RW
+       ntfs_write_inode,
+#else
+       NULL,
+#endif
+       NULL, /* put_inode */
        NULL, /* delete_inode */
        NULL, /* notify_change */
        ntfs_put_super,
@@ -898,7 +1003,7 @@ ntfs_read_super_dec:
  * Define SECOND if you cannot unload ntfs, and want to avoid rebooting
  * for just one more test
  */
-struct file_system_type ntfs_fs_type = {
+static struct file_system_type ntfs_fs_type = {
 /* Filesystem name, as used after mount -t */
 #ifndef SECOND
        "ntfs",
index 4d2ae30c3404443d463d91503ff294790380ebf3..a70205e2fac14d0dbcafbfa47c45e5fa8de888f6 100644 (file)
@@ -1,12 +1,13 @@
 /*
  *  inode.c
  *
- *  Copyright (C) 1995-1997 Martin von Löwis
+ *  Copyright (C) 1995-1999 Martin von Löwis
  *  Copyright (C) 1996 Albert D. Cahalan
  *  Copyright (C) 1996-1997 Régis Duchesne
+ *  Copyright (C) 1998 Joseph Malicki
  */
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "inode.h"
 
@@ -187,7 +188,7 @@ void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno)
 /* Read and insert all the attributes of an 'attribute list' attribute
    Return the number of remaining bytes in *plen
 */
-static int parse_attributes(ntfs_inode *ino, void *alist, int *plen)
+static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen)
 {
        char *mft;
        int mftno,l,error;
@@ -223,14 +224,14 @@ static void ntfs_load_attributes(ntfs_inode* ino)
        int offset,len,delta;
        char *buf;
        ntfs_volume *vol=ino->vol;
-       ntfs_debug(DEBUG_OTHER, "load_attributes %x 1\n",ino->i_number);
+       ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n",ino->i_number);
        ntfs_insert_mft_attributes(ino,ino->attr,ino->i_number);
-       ntfs_debug(DEBUG_OTHER, "load_attributes %x 2\n",ino->i_number);
+       ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n",ino->i_number);
        alist=ntfs_find_attr(ino,vol->at_attribute_list,0);
-       ntfs_debug(DEBUG_OTHER, "load_attributes %x 3\n",ino->i_number);
+       ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n",ino->i_number);
        if(!alist)
                return;
-       ntfs_debug(DEBUG_OTHER, "load_attributes %x 4\n",ino->i_number);
+       ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n",ino->i_number);
        datasize=alist->size;
        if(alist->resident)
        {
@@ -255,7 +256,7 @@ static void ntfs_load_attributes(ntfs_inode* ino)
                        /* move remaining bytes to buffer start */
                        ntfs_memmove(buf,buf+len-delta,delta);
        }
-       ntfs_debug(DEBUG_OTHER, "load_attributes %x 5\n",ino->i_number);
+       ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n",ino->i_number);
        ntfs_free(buf);
 }
        
@@ -264,7 +265,7 @@ int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum)
        char *buf;
        int error;
 
-       ntfs_debug(DEBUG_OTHER, "Initializing inode %x\n",inum);
+       ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n",inum);
        if(!vol)
                ntfs_error("NO VOLUME!\n");
        ino->i_number=inum;
@@ -275,14 +276,14 @@ int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum)
                ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum);
                return error;
        }
-       ntfs_debug(DEBUG_OTHER, "Init: got mft %x\n",inum);
+       ntfs_debug(DEBUG_FILE2, "Init: got mft %x\n",inum);
        ino->sequence_number=NTFS_GETU16(buf+0x10);
        ino->attr_count=0;
        ino->record_count=0;
        ino->records=0;
        ino->attrs=0;
        ntfs_load_attributes(ino);
-       ntfs_debug(DEBUG_OTHER, "Init: done %x\n",inum);
+       ntfs_debug(DEBUG_FILE2, "Init: done %x\n",inum);
        return 0;
 }
 
@@ -391,40 +392,46 @@ ntfs_attr_is_resident(ntfs_inode*ino,int type,char*name)
  * This function decodes a run. Length is an output parameter, data and cluster
  * are in/out parameters.
  */
-int ntfs_decompress_run(unsigned char **data, int *length, int *cluster,
+int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,
        int *ctype)
 {
        unsigned char type=*(*data)++;
        *ctype=0;
        switch(type & 0xF)
        {
-       case 1: *length=NTFS_GETU8(*data);(*data)++;break;
-       case 2: *length=NTFS_GETU16(*data);
-               *data+=2;
-               break;
-       case 3: *length = NTFS_GETU24(*data);
-               *data+=3;
-               break;
-               /* TODO: case 4-8 */
+       case 1: *length=NTFS_GETU8(*data);break;
+       case 2: *length=NTFS_GETU16(*data);break;
+       case 3: *length=NTFS_GETU24(*data);break;
+        case 4: *length=NTFS_GETU32(*data);break;
+               /* Note: cases 5-8 are probably pointless to code,
+                  since how many runs > 4GB of length are there?
+                  at the most, cases 5 and 6 are probably necessary,
+                  and would also require making length 64-bit
+                  throughout */
        default:
                ntfs_error("Can't decode run type field %x\n",type);
                return -1;
        }
+       *data+=(type & 0xF);
+
        switch(type & 0xF0)
        {
-       case 0:    *ctype=2;break;
-       case 0x10: *cluster+=NTFS_GETS8(*data);(*data)++;break;
-       case 0x20: *cluster+=NTFS_GETS16(*data);
-               *data+=2;
-               break;
-       case 0x30:      *cluster+=NTFS_GETS24(*data);
-               *data+=3;
-               break;
-               /* TODO: case 0x40-0x80 */
+       case 0:    *ctype=2; break;
+       case 0x10: *cluster += NTFS_GETS8(*data);break;
+       case 0x20: *cluster += NTFS_GETS16(*data);break;
+       case 0x30: *cluster += NTFS_GETS24(*data);break;
+       case 0x40: *cluster += NTFS_GETS32(*data);break;
+#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit */
+       case 0x50: *cluster += NTFS_GETS40(*data);break;
+       case 0x60: *cluster += NTFS_GETS48(*data);break;
+       case 0x70: *cluster += NTFS_GETS56(*data);break;
+       case 0x80: *cluster += NTFS_GETS64(*data);break;        
+#endif
        default:
                ntfs_error("Can't decode run type field %x\n",type);
                return -1;
        }
+       *data+=(type >> 4);
        return 0;
 }
 
@@ -435,7 +442,8 @@ int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
        ntfs_io *dest)
 {
        int datasize,rnum;
-       int cluster,s_cluster,vcn,len,l,chunk,copied;
+       ntfs_cluster_t cluster,s_cluster,vcn,len;
+       int l,chunk,copied;
        int s_vcn;
        int clustersize;
        int error;
@@ -443,6 +451,8 @@ int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
        clustersize=ino->vol->clustersize;
        datasize=attr->size;
        l=dest->size;
+       if(l==0)
+               return 0;
        if(dest->do_read)
        {
                if(offset>=datasize){
@@ -457,20 +467,30 @@ int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
                        if(error)
                                return error;
                }
+               if (offset+l > attr->initialized)
+                       attr->initialized = offset+l;
        }
        if(attr->resident)
        {
                if(dest->do_read)
-                       dest->fn_put(dest,attr->d.data+offset,l);
+                       dest->fn_put(dest,(ntfs_u8*)attr->d.data+offset,l);
                else
-               {
-                       dest->fn_get(attr->d.data+offset,dest,l);
-                       ntfs_update_inode(ino);
-               }
+                       dest->fn_get((ntfs_u8*)attr->d.data+offset,dest,l);
                dest->size=l;
                return 0;
        }
-       if(attr->compressed) {
+       /* read uninitialized data */
+       if(offset>=attr->initialized && dest->do_read)
+               return ntfs_read_zero(dest,l);
+       if(offset+l>attr->initialized && dest->do_read)
+       {
+               dest->size = chunk = offset+l - attr->initialized;
+               error = ntfs_readwrite_attr(ino,attr,offset,dest);
+               if(error)
+                       return error;           
+               return ntfs_read_zero(dest,l-chunk);
+       }
+       if(attr->compressed){
                if(dest->do_read)
                        return ntfs_read_compressed(ino,attr,offset,dest);
                else
@@ -544,17 +564,26 @@ int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset,
 int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn)
 {
        int rnum;
-       ntfs_attribute *data=ntfs_find_attr(ino,ino->vol->at_data,0);
+       ntfs_attribute *data;
+       ntfs_error("bmap %x\n",vcn);
+       data=ntfs_find_attr(ino,ino->vol->at_data,0);
        /* It's hard to give an error code */
        if(!data)return -1;
        if(data->resident)return -1;
        if(data->compressed)return -1;
-       if(data->size<vcn*ino->vol->clustersize)return -1;
+       if(data->size <= vcn*ino->vol->clustersize)return -1;
+
+
+       /* For Linux, block number 0 represents a hole.
+          Hopefully, nobody will attempt to bmap $Boot. */
+       if(data->initialized <= vcn*ino->vol->clustersize)
+               return 0;
 
        for(rnum=0;rnum<data->d.r.len && 
                    vcn>data->d.r.runlist[rnum].len;rnum++)
                vcn-=data->d.r.runlist[rnum].len;
        
+       ntfs_error("result %x\n",data->d.r.runlist[rnum].cluster+vcn);
        return data->d.r.runlist[rnum].cluster+vcn;
 }
 
@@ -599,7 +628,8 @@ deallocate_store(ntfs_disk_inode* store)
 int 
 layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
 {
-       int i,cluster,rclus,len,offset,coffs;
+       int i,len,offset,coffs;
+       ntfs_cluster_t cluster,rclus;
        ntfs_runlist *rl=attr->d.r.runlist;
        cluster=0;
        offset=*offs;
@@ -610,23 +640,21 @@ layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
                if(offset+8>size)
                        return E2BIG; /* it might still fit, but this simplifies testing */
                if(len<0x100){
-                       *(rec+offset)|=1;
                        NTFS_PUTU8(rec+offset+1,len);
-                       coffs=2;
+                       coffs=1;
                }else if(len<0x10000){
-                       *(rec+offset)|=2;
                        NTFS_PUTU16(rec+offset+1,len);
-                       coffs=3;
+                       coffs=2;
                }else if(len<0x1000000){
-                       *(rec+offset)|=3;
                        NTFS_PUTU24(rec+offset+1,len);
-                       coffs=4;
+                       coffs=3;
                }else{
-                       *(rec+offset)|=4;
                        NTFS_PUTU32(rec+offset+1,len);
-                       coffs=5;
+                       coffs=4;
                }
     
+               *(rec+offset)|=coffs++;
+
                if(rl[i].cluster==0) /*compressed run*/
                        /*nothing*/;
                else if(rclus>-0x80 && rclus<0x7F){
@@ -641,15 +669,42 @@ layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
                        *(rec+offset)|=0x30;
                        NTFS_PUTS24(rec+offset+coffs,rclus);
                        coffs+=3;
-               }else{
+               }else
+#if 0 /* In case ntfs_cluster_t ever becomes 64bit */
+               if (rclus>-0x80000000LL && rclus<0x7FFFFFFF)
+#endif
+               {
                        *(rec+offset)|=0x40;
                        NTFS_PUTS32(rec+offset+coffs,rclus);
                        coffs+=4;
                }
+#if 0 /* For 64-bit ntfs_cluster_t */
+               else if (rclus>-0x8000000000 && rclus<0x7FFFFFFFFF){
+                       *(rec+offset)|=0x50;
+                       NTFS_PUTS40(rec+offset+coffs,rclus);
+                       coffs+=5;
+               }else if (rclus>-0x800000000000 && rclus<0x7FFFFFFFFFFF){
+                       *(rec+offset)|=0x60;
+                       NTFS_PUTS48(rec+offset+coffs,rclus);
+                       coffs+=6;
+               }else if (rclus>-0x80000000000000 && rclus<0x7FFFFFFFFFFFFF){
+                       *(rec+offset)|=0x70;
+                       NTFS_PUTS56(rec+offset+coffs,rclus);
+                       coffs+=7;
+               }else{
+                       *(rec+offset)|=0x80;
+                       NTFS_PUTS64(rec+offset+coffs,rclus);
+                       coffs+=8;
+               }
+#endif
                offset+=coffs;
                if(rl[i].cluster)
                        cluster=rl[i].cluster;
        }
+       if(offset>=size)
+               return E2BIG;
+       /* terminating null */
+       *(rec+offset++)=0;
        *offs=offset;
        return 0;
 }
@@ -657,14 +712,14 @@ layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
 static void 
 count_runs(ntfs_attribute *attr,char *buf)
 {
-       int first,count,last,i;
+       ntfs_u32 first,count,last,i;
        first=0;
        for(i=0,count=0;i<attr->d.r.len;i++)
                count+=attr->d.r.runlist[i].len;
        last=first+count-1;
 
-       NTFS_PUTU32(buf+0x10,first);
-       NTFS_PUTU32(buf+0x18,last);
+       NTFS_PUTU64(buf+0x10,first);
+       NTFS_PUTU64(buf+0x18,last);
 } 
 
 static int
@@ -814,8 +869,17 @@ int ntfs_update_inode(ntfs_inode *ino)
        store.records=0;
        error=layout_inode(ino,&store);
        if(error==E2BIG){
+               error = ntfs_split_indexroot(ino);
+               if(!error)
+                       error = layout_inode(ino,&store);
+       }
+       if(error == E2BIG){
+               error = ntfs_attr_allnonresident(ino);
+               if(!error)
+                       error = layout_inode(ino,&store);
+       }
+       if(error == E2BIG){
                /* should try:
-                  make attributes non-resident
                   introduce extension records
                   */
                ntfs_error("cannot handle saving inode %x\n",ino->i_number);
@@ -844,7 +908,8 @@ int ntfs_update_inode(ntfs_inode *ino)
                }
        }
        return 0;
-}
+}      
+
 
 void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l)
 {
@@ -1030,7 +1095,7 @@ add_standard_information (ntfs_inode *ino)
 
 static int 
 add_filename (ntfs_inode* ino, ntfs_inode* dir, 
-                        const unsigned char *filename, int length)
+             const unsigned char *filename, int length, ntfs_u32 flags)
 {
        unsigned char   *position;
        unsigned int    size;
@@ -1057,7 +1122,7 @@ add_filename (ntfs_inode* ino, ntfs_inode* dir,
        NTFS_PUTU64(position + 0x20, now);              /* Last access */
 
        /* Don't know */
-       NTFS_PUTU8(position+0x38, 0x0);  /*should match standard attributes*/
+       NTFS_PUTU32(position+0x38, flags);
 
        NTFS_PUTU8(position + 0x40, length);          /* Filename length */
        NTFS_PUTU8(position + 0x41, 0x0);             /* only long name */
@@ -1120,10 +1185,9 @@ add_data (ntfs_inode* ino, unsigned char *data, int length)
        return error;
 }
 
-
 /* We _could_ use 'dir' to help optimise inode allocation */
-int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, char *filename,
-               int namelen)
+int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, 
+                     const char *filename, int namelen, ntfs_u32 flags)
 {
        ntfs_io io;
        int error;
@@ -1185,15 +1249,23 @@ int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, char *filename,
        error=add_standard_information(result);
        if(error)
                return error;
-       error=add_filename(result,dir,filename,namelen);
+       error=add_filename(result,dir,filename,namelen,flags);
        if(error)
                return error;
        error=add_security(result,dir);
        /*FIXME: check error */
-       error=add_data(result,0,0);
+       return 0;
+}
+
+int
+ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
+               int namelen)
+{
+       int error = ntfs_alloc_inode(dir,result,filename,namelen,0);
        if(error)
                return error;
-       return 0;
+       error = add_data(result,0,0);
+       return error;
 }
 
 /*
index f73fa5bff518eb970f247944342d5d599ea2da11..60694421116056e77d656ab3c9cb7a93b20a342b 100644 (file)
@@ -3,23 +3,26 @@
  *  Header file for inode.c
  *
  *  Copyright (C) 1997 Régis Duchesne
+ *  Copyright (C) 1998 Martin von Löwis
  */
 
 ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name);
 int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset,
-  ntfs_io *buf);
+                  ntfs_io *buf);
 int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset,
-  ntfs_io *buf);
+                   ntfs_io *buf);
 int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum);
 void ntfs_clear_inode(ntfs_inode *ino);
 int ntfs_check_mft_record(ntfs_volume *vol,char *record);
-int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, char *filename,
-  int namelen);
+int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result, 
+                     const char *filename, int namelen,ntfs_u32);
+int ntfs_alloc_file (ntfs_inode *dir, ntfs_inode *result, 
+                    char *filename, int namelen);
 int ntfs_update_inode(ntfs_inode *ino);
 int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn);
 int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
-  ntfs_io *dest);
+                       ntfs_io *dest);
 int ntfs_allocate_attr_number(ntfs_inode *ino, int *result);
-int ntfs_decompress_run(unsigned char **data, int *length, int *cluster,
-  int *ctype);
+int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,
+                       int *ctype);
 void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l);
index 964e63c86ae9a2ca09df67f989b1c2e87b6bac72..fae6ae9aa2db9f6ac29ff94388b528e921f69685 100644 (file)
 #define NTFS_V2INO(ino)                ((ntfs_inode*)((ino)->v_data))
 
 /* Classical min and max macros still missing in standard headers... */
+#ifndef min
 #define min(a,b)       ((a) <= (b) ? (a) : (b))
 #define max(a,b)       ((a) >= (b) ? (a) : (b))
+#endif
 
 #define IS_MAGIC(a,b)          (*(int*)(a)==*(int*)(b))
 #define IS_MFT_RECORD(a)       IS_MAGIC((a),"FILE")
 /* 'NTFS' in little endian */
 #define NTFS_SUPER_MAGIC       0x5346544E
 
+#define NTFS_AFLAG_RO           1
+#define NTFS_AFLAG_HIDDEN       2
+#define NTFS_AFLAG_SYSTEM       4
+#define NTFS_AFLAG_ARCHIVE      20
+#define NTFS_AFLAG_COMPRESSED   0x800
+#define NTFS_AFLAG_DIR          0x10000000
+
 /*
  * Local variables:
  *  c-file-style: "linux"
diff --git a/fs/ntfs/ntfsendian.h b/fs/ntfs/ntfsendian.h
new file mode 100644 (file)
index 0000000..13af76a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  ntfsendian.h
+ *
+ *  Copyright (C) 1998 Martin von Löwis
+ *  Copyright (C) 1998 Joseph Malicki
+ */
+
+#ifdef __linux__
+/* This defines __cpu_to_le16 on Linux 2.1 and higher. */
+#include <asm/byteorder.h>
+#endif
+
+#ifdef __cpu_to_le16
+#define CPU_TO_LE16(a) __cpu_to_le16(a)
+#define CPU_TO_LE32(a) __cpu_to_le32(a)
+#define CPU_TO_LE64(a) __cpu_to_le64(a)
+
+#define LE16_TO_CPU(a) __cpu_to_le16(a)
+#define LE32_TO_CPU(a) __cpu_to_le32(a)
+#define LE64_TO_CPU(a) __cpu_to_le64(a)
+
+#else
+
+#ifdef __LITTLE_ENDIAN
+
+#define CPU_TO_LE16(a) (a)
+#define CPU_TO_LE32(a) (a)
+#define CPU_TO_LE64(a) (a)
+#define LE16_TO_CPU(a) (a)
+#define LE32_TO_CPU(a) (a)
+#define LE64_TO_CPU(a) (a)
+
+#else
+
+/* Routines for big-endian machines */
+#ifdef __BIG_ENDIAN
+
+/* We hope its big-endian, not PDP-endian :) */
+#define CPU_TO_LE16(a) ((((a)&0xF) << 8)|((a) >> 8))
+#define CPU_TO_LE32(a) ((((a) & 0xF) << 24) | (((a) & 0xF0) << 8) | \
+                       (((a) & 0xF00) >> 8) | ((a) >> 24))
+#define CPU_TO_LE64(a) ((CPU_TO_LE32(a)<<32)|CPU_TO_LE32((a)>>32)
+
+#define LE16_TO_CPU(a) CPU_TO_LE16(a)
+#define LE32_TO_CPU(a) CPU_TO_LE32(a)
+#define LE64_TO_CPU(a) CPU_TO_LE64(a)
+
+#else
+
+#error Please define Endianness - __BIG_ENDIAN or __LITTLE_ENDIAN or add OS-specific macros
+
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+#endif /* __cpu_to_le16 */
+
+#define NTFS_GETU8(p)      (*(ntfs_u8*)(p))
+#define NTFS_GETU16(p)     ((ntfs_u16)LE16_TO_CPU(*(ntfs_u16*)(p)))
+#define NTFS_GETU24(p)     (NTFS_GETU32(p) & 0xFFFFFF)
+#define NTFS_GETU32(p)     ((ntfs_u32)LE32_TO_CPU(*(ntfs_u32*)(p)))
+#define NTFS_GETU40(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU8(((char*)(p))+4))<<32))
+#define NTFS_GETU48(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU16(((char*)(p))+4))<<32))
+#define NTFS_GETU56(p)     ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU24(((char*)(p))+4))<<32))
+#define NTFS_GETU64(p)     ((ntfs_u64)LE64_TO_CPU(*(ntfs_u64*)(p)))
+ /* Macros writing unsigned integers */
+#define NTFS_PUTU8(p,v)      ((*(ntfs_u8*)(p))=(v))
+#define NTFS_PUTU16(p,v)     ((*(ntfs_u16*)(p))=CPU_TO_LE16(v))
+#define NTFS_PUTU24(p,v)     NTFS_PUTU16(p,(v) & 0xFFFF);\
+                             NTFS_PUTU8(((char*)(p))+2,(v)>>16)
+#define NTFS_PUTU32(p,v)     ((*(ntfs_u32*)(p))=CPU_TO_LE32(v))
+#define NTFS_PUTU64(p,v)     ((*(ntfs_u64*)(p))=CPU_TO_LE64(v))
+ /* Macros reading signed integers */
+#define NTFS_GETS8(p)        ((*(ntfs_u8*)(p)))
+#define NTFS_GETS16(p)       ((ntfs_s16)LE16_TO_CPU(*(short*)(p)))
+#define NTFS_GETS24(p)       (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) - 0x1000000))
+#define NTFS_GETS32(p)       ((ntfs_s32)LE32_TO_CPU(*(int*)(p)))
+#define NTFS_GETS40(p)       (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS8(((char*)(p))+4)) << 32))
+#define NTFS_GETS48(p)       (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS16(((char*)(p))+4)) << 32))
+#define NTFS_GETS56(p)       (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS24(((char*)(p))+4)) << 32))
+#define NTFS_GETS64(p)      ((ntfs_s64)NTFS_GETU64(p))
+#define NTFS_PUTS8(p,v)      NTFS_PUTU8(p,v)
+#define NTFS_PUTS16(p,v)     NTFS_PUTU16(p,v)
+#define NTFS_PUTS24(p,v)     NTFS_PUTU24(p,v)
+#define NTFS_PUTS32(p,v)     NTFS_PUTU32(p,v)
diff --git a/fs/ntfs/ntfstypes.h b/fs/ntfs/ntfstypes.h
new file mode 100644 (file)
index 0000000..e88a416
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  types.h
+ *  This file defines four things:
+ *   - generic platform independent fixed-size types (e.g. ntfs_u32)
+ *   - specific fixed-size types (e.g. ntfs_offset_t)
+ *   - macros that read and write those types from and to byte arrays
+ *   - types derived from OS specific ones
+ *
+ *  Copyright (C) 1996,1998 Martin von Löwis
+ */
+
+#ifdef NTFS_IN_LINUX_KERNEL
+/* get installed types if we compile the kernel*/
+#include <linux/fs.h>
+#endif
+
+/* We don't need to define __LITTLE_ENDIAN, as we use
+   <asm/byteorder>. */
+
+#include "ntfsendian.h"
+#include <asm/types.h>
+
+/* integral types */
+#ifndef NTFS_INTEGRAL_TYPES
+#define NTFS_INTEGRAL_TYPES
+typedef u8  ntfs_u8;
+typedef u16 ntfs_u16;
+typedef u32 ntfs_u32;
+typedef u64 ntfs_u64;
+typedef s8  ntfs_s8;
+typedef s16 ntfs_s16;
+typedef s32 ntfs_s32;
+typedef s64 ntfs_s64;
+#endif
+
+/* unicode character type */
+#ifndef NTFS_WCHAR_T
+#define NTFS_WCHAR_T
+typedef u16 ntfs_wchar_t;
+#endif
+/* file offset */
+#ifndef NTFS_OFFSET_T
+#define NTFS_OFFSET_T
+typedef u64 ntfs_offset_t;
+#endif
+/* UTC */
+#ifndef NTFS_TIME64_T
+#define NTFS_TIME64_T
+typedef u64 ntfs_time64_t;
+#endif
+/* This is really unsigned long long. So we support only volumes up to 2 TB */
+#ifndef NTFS_CLUSTER_T
+#define NTFS_CLUSTER_T
+typedef u32 ntfs_cluster_t;
+#endif
+
+/* architecture independent macros */
+
+/* PUTU32 would not clear all bytes */
+#define NTFS_PUTINUM(p,i)    NTFS_PUTU64(p,i->i_number);\
+                             NTFS_PUTU16(((char*)p)+6,i->sequence_number)
+
+/* system dependent types */
+#include <asm/posix_types.h>
+#ifndef NTMODE_T
+#define NTMODE_T
+typedef __kernel_mode_t ntmode_t;
+#endif
+#ifndef NTFS_UID_T
+#define NTFS_UID_T
+typedef __kernel_uid_t ntfs_uid_t;
+#endif
+#ifndef NTFS_GID_T
+#define NTFS_GID_T
+typedef __kernel_gid_t ntfs_gid_t;
+#endif
+#ifndef NTFS_SIZE_T
+#define NTFS_SIZE_T
+typedef __kernel_size_t ntfs_size_t;
+#endif
+#ifndef NTFS_TIME_T
+#define NTFS_TIME_T
+typedef __kernel_time_t ntfs_time_t;
+#endif
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
index be1aedbea0f7289145571689c66fecc75f3ccc86..797a60791bb0e71026f065c48db8840f187db3e5 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 1996-1997 Régis Duchesne
  */
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "super.h"
 
@@ -32,7 +32,7 @@
 int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size)
 {
        int start, count, offset;
-       unsigned short fixup;
+       ntfs_u16 fixup;
 
        if(!IS_MAGIC(record,magic))
                return 0;
@@ -116,7 +116,7 @@ ntfs_init_upcase(ntfs_inode *upcase)
        upcase->vol->upcase_length = UPCASE_LENGTH;
        io.fn_put=ntfs_put;
        io.fn_get=0;
-       io.param=upcase->vol->upcase;
+       io.param=(char*)upcase->vol->upcase;
        io.size=2*UPCASE_LENGTH;
        ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io);
 }
@@ -152,8 +152,8 @@ process_attrdef(ntfs_inode* attrdef,ntfs_u8* def)
        }else if(ntfs_ua_strncmp(name,"$BITMAP",64)==0){
                vol->at_bitmap=type;
                check_type=0xB0;
-       }else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64) ||
-                ntfs_ua_strncmp(name,"$REPARSE_POINT",64)){
+       }else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64)==0 ||
+                ntfs_ua_strncmp(name,"$REPARSE_POINT",64)==0){
                vol->at_symlink=type;
        }
        if(check_type && check_type!=type){
@@ -170,7 +170,7 @@ ntfs_init_attrdef(ntfs_inode* attrdef)
        ntfs_io io;
        int offset,error,i;
        ntfs_attribute *data;
-       buf=ntfs_malloc(4096);
+       buf=ntfs_malloc(4050); /* 90*45 */
        if(!buf)return ENOMEM;
        io.fn_put=ntfs_put;
        io.fn_get=ntfs_get;
@@ -183,9 +183,9 @@ ntfs_init_attrdef(ntfs_inode* attrdef)
        }
        do{
                io.param=buf;
-               io.size=4096;
+               io.size=4050;
                error=ntfs_readwrite_attr(attrdef,data,offset,&io);
-               for(i=0;!error && i<io.size;i+=0xA0)
+               for(i=0;!error && i<io.size-0xA0;i+=0xA0)
                        error=process_attrdef(attrdef,buf+i);
                offset+=4096;
        }while(!error && io.size);
@@ -200,25 +200,30 @@ int ntfs_load_special_files(ntfs_volume *vol)
 
        vol->mft_ino=(ntfs_inode*)ntfs_calloc(3*sizeof(ntfs_inode));
        error=ENOMEM;
+       ntfs_debug(DEBUG_BSD,"Going to load MFT\n");
        if(!vol->mft_ino || (error=ntfs_init_inode(vol->mft_ino,vol,FILE_MFT)))
        {
                ntfs_error("Problem loading MFT\n");
                return error;
        }
+       ntfs_debug(DEBUG_BSD,"Going to load MIRR\n");
        vol->mftmirr=vol->mft_ino+1;
        if((error=ntfs_init_inode(vol->mftmirr,vol,FILE_MFTMIRR))){
                ntfs_error("Problem %d loading MFTMirr\n",error);
                return error;
        }
+       ntfs_debug(DEBUG_BSD,"Going to load BITMAP\n");
        vol->bitmap=vol->mft_ino+2;
        if((error=ntfs_init_inode(vol->bitmap,vol,FILE_BITMAP))){
                ntfs_error("Problem loading Bitmap\n");
                return error;
        }
+       ntfs_debug(DEBUG_BSD,"Going to load UPCASE\n");
        error=ntfs_init_inode(&upcase,vol,FILE_UPCASE);
        if(error)return error;
        ntfs_init_upcase(&upcase);
        ntfs_clear_inode(&upcase);
+       ntfs_debug(DEBUG_BSD,"Going to load ATTRDEF\n");
        error=ntfs_init_inode(&attrdef,vol,FILE_ATTRDEF);
        if(error)return error;
        error=ntfs_init_attrdef(&attrdef);
@@ -245,7 +250,7 @@ int ntfs_get_volumesize(ntfs_volume *vol)
 {
        ntfs_io io;
        char *cluster0=ntfs_malloc(vol->clustersize);
-       int size;
+       ntfs_u64 size;
 
        io.fn_put=ntfs_put;
        io.fn_get=ntfs_get;
@@ -255,8 +260,9 @@ int ntfs_get_volumesize(ntfs_volume *vol)
        ntfs_getput_clusters(vol,0,0,&io);
        size=NTFS_GETU64(cluster0+0x28);
        ntfs_free(cluster0);
-       size/=vol->clusterfactor;
-       return size;
+       /* FIXME: more than 2**32 cluster */
+       /* FIXME: gcc will emit udivdi3 if we don't truncate it */
+       return ((unsigned int)size)/vol->clusterfactor;
 }
 
 static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
@@ -323,7 +329,7 @@ void ntfs_insert_fixups(unsigned char *rec, int secsize)
    Return the largest block found in *cnt. Return 0 on success, ENOSPC if
    all bits are used */
 static int 
-search_bits(unsigned char* bits,int *loc,int *cnt,int l)
+search_bits(unsigned char* bits,ntfs_cluster_t *loc,int *cnt,int l)
 {
        unsigned char c=0;
        int bc=0;
@@ -384,7 +390,7 @@ search_bits(unsigned char* bits,int *loc,int *cnt,int l)
 }
 
 int 
-ntfs_set_bitrange(ntfs_inode* bitmap,int loc,int cnt,int bit)
+ntfs_set_bitrange(ntfs_inode* bitmap,ntfs_cluster_t loc,int cnt,int bit)
 {
        int bsize,locit,error;
        unsigned char *bits,*it;
@@ -392,13 +398,13 @@ ntfs_set_bitrange(ntfs_inode* bitmap,int loc,int cnt,int bit)
 
        io.fn_put=ntfs_put;
        io.fn_get=ntfs_get;
-       bsize=(cnt+loc%8+7)/8; /* round up */
+       bsize=(cnt+(loc & 7)+7) & ~7; /* round up to multiple of 8*/
        bits=ntfs_malloc(bsize);
        io.param=bits;
        io.size=bsize;
        if(!bits)
                return ENOMEM;
-       error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,loc/8,&io);
+       error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io);
        if(error || io.size!=bsize){
                ntfs_free(bits);
                return error?error:EIO;
@@ -431,7 +437,7 @@ ntfs_set_bitrange(ntfs_inode* bitmap,int loc,int cnt,int bit)
        /* reset to start */
        io.param=bits;
        io.size=bsize;
-       error=ntfs_write_attr(bitmap,bitmap->vol->at_data,0,loc/8,&io);
+       error=ntfs_write_attr(bitmap,bitmap->vol->at_data,0,loc>>3,&io);
        ntfs_free(bits);
        if(error)return error;
        if(io.size!=bsize)
@@ -445,7 +451,7 @@ ntfs_set_bitrange(ntfs_inode* bitmap,int loc,int cnt,int bit)
    it does not matter where the clusters are. Result is 0 if
    success, in which case location and count says what they really got */
 int 
-ntfs_search_bits(ntfs_inode* bitmap, int *location, int *count, int flags)
+ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count, int flags)
 {
        unsigned char *bits;
        ntfs_io io;
@@ -459,7 +465,7 @@ ntfs_search_bits(ntfs_inode* bitmap, int *location, int *count, int flags)
        io.param=bits;
 
        /* first search within +/- 8192 clusters */
-       start=*location/8;
+       start=*location>>3;
        start= start>1024 ? start-1024 : 0;
        io.size=2048;
        error=ntfs_read_attr(bitmap,bitmap->vol->at_data,0,start,&io);
@@ -483,7 +489,7 @@ ntfs_search_bits(ntfs_inode* bitmap, int *location, int *count, int flags)
                error=ntfs_read_attr(bitmap,bitmap->vol->at_data,
                                     0,start,&io);
                if(error)goto fail;
-               if(io.size==0) {
+               if(io.size==0){
                        if(found)
                                goto success;
                        else{
@@ -524,7 +530,7 @@ ntfs_search_bits(ntfs_inode* bitmap, int *location, int *count, int flags)
        return error;
 }
 
-int ntfs_allocate_clusters(ntfs_volume *vol, int *location, int *count,
+int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count,
        int flags)
 {
        int error;
@@ -532,7 +538,7 @@ int ntfs_allocate_clusters(ntfs_volume *vol, int *location, int *count,
        return error;
 }
 
-int ntfs_deallocate_clusters(ntfs_volume *vol, int location, int count)
+int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count)
 {
        int error;
        error=ntfs_set_bitrange(vol->bitmap,location,count,0);
index c49245089a21528f5fa0654e63d320580cf8e120..f9049013659066f303646e4213a19233f65c0bef 100644 (file)
@@ -16,6 +16,6 @@ int ntfs_load_special_files(ntfs_volume *vol);
 int ntfs_release_volume(ntfs_volume *vol);
 void ntfs_insert_fixups(unsigned char *rec, int secsize);
 int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size);
-int ntfs_allocate_clusters(ntfs_volume *vol, int *location, int *count,
+int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location, int *count,
   int flags);
-int ntfs_deallocate_clusters(ntfs_volume *vol, int location, int count);
+int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location, int count);
index 1dfe62d5029e0d663cdd89be0f3f655224143ca5..e0b79c8deedb70e8077099d63386762ab90172b1 100644 (file)
@@ -7,7 +7,10 @@
  *
  */
 
-#include "types.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ntfstypes.h"
 #include "struct.h"
 #include "support.h"
 
@@ -86,17 +89,20 @@ void ntfs_bzero(void *s, int n)
        memset(s, 0, n);
 }
 
-void *ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
+/* These functions deliberately return no value. It is dest, anyway,
+   and not used anywhere in the NTFS code.  */
+
+void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
 {
-       return memcpy(dest, src, n);
+       memcpy(dest, src, n);
 }
 
-void *ntfs_memmove(void *dest, const void *src, ntfs_size_t n)
+void ntfs_memmove(void *dest, const void *src, ntfs_size_t n)
 {
-       return memmove(dest, src, n);
+       memmove(dest, src, n);
 }
 
-/* Warn that an error occurred. */
+/* Warn that an error occured. */
 void ntfs_error(const char *fmt,...)
 {
         va_list ap;
index b6def5c5639489922eed529ffdf4dd4d2f4f79e5..329511fabd38f68489880832d1d9c76bf50dc08d 100644 (file)
@@ -8,6 +8,16 @@
 /* Debug levels */
 #define DEBUG_OTHER    1
 #define DEBUG_MALLOC   2
+#define DEBUG_BSD       4
+#define DEBUG_LINUX     8
+#define DEBUG_DIR1     16
+#define DEBUG_DIR2     32
+#define DEBUG_DIR3     64
+#define DEBUG_FILE1   128
+#define DEBUG_FILE2   256
+#define DEBUG_FILE3   512
+#define DEBUG_NAME1  1024
+#define DEBUG_NAME2  2048
 
 void ntfs_debug(int mask, const char *fmt, ...);
 #ifdef NTFS_IN_LINUX_KERNEL
@@ -19,8 +29,8 @@ void *ntfs_malloc(int size);
 void ntfs_free(void *block);
 #endif
 void ntfs_bzero(void *s, int n);
-void *ntfs_memcpy(void *dest, const void *src, ntfs_size_t n);
-void *ntfs_memmove(void *dest, const void *src, ntfs_size_t n);
+void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n);
+void ntfs_memmove(void *dest, const void *src, ntfs_size_t n);
 void ntfs_error(const char *fmt,...);
 int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf);
 int ntfs_getput_clusters(ntfs_volume *pvol, int cluster, ntfs_size_t offs,
index 082e34abaed9d33e8790fb7b54bb0c5a2bfcadc9..e2a02086b3416fd9df59270da6ee88c8ca357023 100644 (file)
@@ -7,6 +7,10 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #ifdef DEBUG
 extern int ntdebug;
 
diff --git a/fs/ntfs/types.h b/fs/ntfs/types.h
deleted file mode 100644 (file)
index eabcd85..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- *  types.h
- *  This file defines four things:
- *   - generic platform independent fixed-size types (e.g. ntfs_u32)
- *   - specific fixed-size types (e.g. ntfs_offset_t)
- *   - macros that read and write those types from and to byte arrays
- *   - types derived from OS specific ones
- *
- *  Copyright (C) 1996 Martin von Löwis
- */
-
-#ifdef NTFS_IN_LINUX_KERNEL
-/* get installed types if we compile the kernel*/
-#include <linux/fs.h>
-#endif
-
-#if defined(i386) || defined(__i386__) || defined(__alpha__)
-
-/* unsigned integral types */
-#ifndef NTFS_INTEGRAL_TYPES
-#define NTFS_INTEGRAL_TYPES
-typedef unsigned char      ntfs_u8;
-typedef unsigned short     ntfs_u16;
-typedef unsigned int       ntfs_u32;
-typedef unsigned long long ntfs_u64;
-#endif
-
-/* unicode character type */
-#ifndef NTFS_WCHAR_T
-#define NTFS_WCHAR_T
-typedef unsigned short     ntfs_wchar_t;
-#endif
-/* file offset */
-#ifndef NTFS_OFFSET_T
-#define NTFS_OFFSET_T
-typedef unsigned long long ntfs_offset_t;
-#endif
-/* UTC */
-#ifndef NTFS_TIME64_T
-#define NTFS_TIME64_T
-typedef unsigned long long ntfs_time64_t;
-#endif
-/* This is really unsigned long long. So we support only volumes up to 2 TB */
-#ifndef NTFS_CLUSTER_T
-#define NTFS_CLUSTER_T
-typedef unsigned int ntfs_cluster_t;
-#endif
-
-/* Macros reading unsigned integers from a byte pointer */
-/* these should work for all little endian machines */
-#define NTFS_GETU8(p)      (*(ntfs_u8*)(p))
-#define NTFS_GETU16(p)     (*(ntfs_u16*)(p))
-#define NTFS_GETU24(p)     (NTFS_GETU32(p) & 0xFFFFFF)
-#define NTFS_GETU32(p)     (*(ntfs_u32*)(p))
-#define NTFS_GETU64(p)     (*(ntfs_u64*)(p))
-
-/* Macros writing unsigned integers */
-#define NTFS_PUTU8(p,v)      (*(ntfs_u8*)(p))=(v)
-#define NTFS_PUTU16(p,v)     (*(ntfs_u16*)(p))=(v)
-#define NTFS_PUTU24(p,v)     NTFS_PUTU16(p,(v) & 0xFFFF);\
-                             NTFS_PUTU8(((char*)p)+2,(v)>>16)
-#define NTFS_PUTU32(p,v)     (*(ntfs_u32*)(p))=(v)
-#define NTFS_PUTU64(p,v)     (*(ntfs_u64*)(p))=(v)
-
-/* Macros reading signed integers, returning int */
-#define NTFS_GETS8(p)        ((int)(*(char*)(p)))
-#define NTFS_GETS16(p)       ((int)(*(short*)(p)))
-#define NTFS_GETS24(p)       (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) | 0xFF000000))
-
-#define NTFS_PUTS8(p,v)      NTFS_PUTU8(p,v)
-#define NTFS_PUTS16(p,v)     NTFS_PUTU16(p,v)
-#define NTFS_PUTS24(p,v)     NTFS_PUTU24(p,v)
-#define NTFS_PUTS32(p,v)     NTFS_PUTU32(p,v)
-
-#else
-#error Put your machine description here
-#endif
-
-/* architecture independent macros */
-
-/* PUTU32 would not clear all bytes */
-#define NTFS_PUTINUM(p,i)    NTFS_PUTU64(p,i->i_number);\
-                             NTFS_PUTU16(((char*)p)+6,i->sequence_number)
-
-/* system dependent types */
-#ifdef __linux__
-/* We always need kernel types, because glibc makes them of different size */
-#include <asm/posix_types.h>
-/* Avoid a type redefinition with future include of glibc <stdlib.h> */
-#undef __FD_ZERO
-#undef __FD_SET
-#undef __FD_CLR
-#undef __FD_ISSET
-#ifndef NTMODE_T
-#define NTMODE_T
-typedef __kernel_mode_t ntmode_t;
-#endif
-#ifndef NTFS_UID_T
-#define NTFS_UID_T
-typedef __kernel_uid_t ntfs_uid_t;
-#endif
-#ifndef NTFS_GID_T
-#define NTFS_GID_T
-typedef __kernel_gid_t ntfs_gid_t;
-#endif
-#ifndef NTFS_SIZE_T
-#define NTFS_SIZE_T
-typedef __kernel_size_t ntfs_size_t;
-#endif
-#ifndef NTFS_TIME_T
-#define NTFS_TIME_T
-typedef __kernel_time_t ntfs_time_t;
-#endif
-#else
-#include <sys/types.h>
-#include <sys/stat.h>
-typedef mode_t ntmode_t;
-typedef uid_t ntfs_uid_t;
-typedef gid_t ntfs_gid_t;
-typedef size_t ntfs_size_t;
-typedef time_t ntfs_time_t;
-#endif
-
-/*
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 4c5d456a7f6248558c82fb95bf3d8c880a257ef4..d6d7921eb8ad74168bf80014dd20c69097652c52 100644 (file)
@@ -2,13 +2,13 @@
  *  util.c
  *  Miscellaneous support
  *
- *  Copyright (C) 1997 Martin von Löwis
+ *  Copyright (C) 1997,1999 Martin von Löwis
  *  Copyright (C) 1997 Régis Duchesne
  *
- *  The utf8 routines are copied from Python wstrop module,
+ *  The utf8 routines are copied from Python wstrop module.
  */
 
-#include "types.h"
+#include "ntfstypes.h"
 #include "struct.h"
 #include "util.h"
 
@@ -20,6 +20,7 @@
 #include "support.h"
 
 /* Converts a single wide character to a sequence of utf8 bytes.
+ * The character is represented in host byte order.
  * Returns the number of bytes, or 0 on error.
  */
 static int
@@ -28,7 +29,7 @@ to_utf8(ntfs_u16 c,unsigned char* buf)
        if(c==0)
                return 0; /* No support for embedded 0 runes */
        if(c<0x80){
-               if(buf)buf[0]=c;
+               if(buf)buf[0]=(unsigned char)c;
                return 1;
        }
        if(c<0x800){
@@ -51,7 +52,8 @@ to_utf8(ntfs_u16 c,unsigned char* buf)
 }
 
 /* Decodes a sequence of utf8 bytes into a single wide character.
- * Returns the number of bytes consumed, or 0 on error
+ * The character is returned in host byte order.
+ * Returns the number of bytes consumed, or 0 on error.
  */
 static int
 from_utf8(const unsigned char* str,ntfs_u16 *c)
@@ -98,10 +100,10 @@ static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len)
        int len8;
        unsigned char *result;
 
-       ntfs_debug(DEBUG_OTHER,"converting l=%d\n",in_len);
+       ntfs_debug(DEBUG_NAME1,"converting l=%d\n",in_len);
        /* count the length of the resulting UTF-8 */
        for(i=len8=0;i<in_len;i++){
-               tmp=to_utf8(in[i],0);
+               tmp=to_utf8(NTFS_GETU16(in+i),0);
                if(!tmp)
                        /* invalid character */
                        return EILSEQ;
@@ -114,7 +116,8 @@ static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len)
        result[len8]='\0';
        *out_len=len8;
        for(i=len8=0;i<in_len;i++)
-               len8+=to_utf8(in[i],result+len8);
+               len8+=to_utf8(NTFS_GETU16(in+i),result+len8);
+       ntfs_debug(DEBUG_NAME1,"result %p:%s\n",result,result);
        return 0;
 }
 
@@ -139,7 +142,10 @@ static int ntfs_duputf82uni(unsigned char* in, int in_len,ntfs_u16** out,int *ou
        result[len16]=0;
        *out_len=len16;
        for(i=len16=0;i<in_len;i+=tmp,len16++)
-               tmp=from_utf8(in+i,result+len16);
+       {
+               tmp=from_utf8(in+i, &wtmp);
+               NTFS_PUTU16(result+len16, wtmp);
+       }
        return 0;
 }
 
@@ -151,7 +157,7 @@ static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len)
 
        /* check for characters out of range */
        for(i=0;i<in_len;i++)
-               if(in[i]>=256)
+               if(NTFS_GETU16(in+i)>=256)
                        return EILSEQ;
        *out=result=ntfs_malloc(in_len+1);
        if(!result)
@@ -159,7 +165,7 @@ static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len)
        result[in_len]='\0';
        *out_len=in_len;
        for(i=0;i<in_len;i++)
-               result[i]=in[i];
+               result[i]=(unsigned char)NTFS_GETU16(in+i);
        return 0;
 }
 
@@ -174,7 +180,7 @@ static int ntfs_dup885912uni(unsigned char* in,int in_len,ntfs_u16 **out,int *ou
                return ENOMEM;
        *out_len=in_len;
        for(i=0;i<in_len;i++)
-               result[i]=in[i];
+               NTFS_PUTU16(result+i,in[i]);
        return 0;
 }
 
@@ -210,19 +216,18 @@ int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len,
 void ntfs_put(ntfs_io *dest,void *src,ntfs_size_t n)
 {
        ntfs_memcpy(dest->param,src,n);
-       dest->param+=n;
+       ((char*)dest->param)+=n;
 }
 
 void ntfs_get(void* dest,ntfs_io *src,ntfs_size_t n)
 {
        ntfs_memcpy(dest,src->param,n);
-       src->param+=n;
+       ((char*)src->param)+=n;
 }
 
 void *ntfs_calloc(int size)
 {
        void *result=ntfs_malloc(size);
-
        if(result)
                ntfs_bzero(result,size);
        return result;
@@ -272,9 +277,9 @@ int ntfs_ua_strncmp(short int* a,char* b,int n)
 
        for(i=0;i<n;i++)
        {
-               if(a[i]<b[i])
+               if(NTFS_GETU16(a+i)<b[i])
                        return -1;
-               if(b[i]<a[i])
+               if(b[i]<NTFS_GETU16(a+i))
                        return 1;
        }
        return 0;
@@ -292,7 +297,7 @@ ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
  * 3: Floating point math in the kernel would corrupt user data
  */
        const unsigned int D = 10000000;
-       unsigned int H = (ntutc >> 32);
+       unsigned int H = (unsigned int)(ntutc >> 32);
        unsigned int L = (unsigned int)ntutc;
        unsigned int numerator2;
        unsigned int lowseconds;
@@ -336,6 +341,25 @@ ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
        return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000);
 }
 
+/* Fill index name. */
+
+void
+ntfs_indexname(char *buf, int type)
+{
+       char hex[]="0123456789ABCDEF";
+       int index;
+       *buf++='$';
+       *buf++='I';
+       for (index=24; index>0; index-=4)
+               if((0xF << index) & type)
+                       break;
+       while(index>=0) {
+               *buf++ = hex[(type >> index) & 0xF];
+               index-=4;
+       }
+       *buf='\0';
+}
+
 /*
  * Local variables:
  * c-file-style: "linux"
index e929abe27282563f849a169ce261cd746cca1fc9..663b0b5da76614f02e5eb9cd2eb61e4665774650 100644 (file)
@@ -56,6 +56,9 @@ int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len, ntfs_u16 **out, int *o
 ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc);
 ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t);
 
+/* Attribute names */
+void ntfs_indexname(char *buf, int type);
+
 /*
  * Local variables:
  * c-file-style: "linux"
index 5537a35e6a4689bcbfb8fee11e4567541bafb252..c6d0032c5190f0ab54bf6febbdc92dd56fa8da24 100644 (file)
@@ -23,7 +23,6 @@ EXPORT_SYMBOL(remove_proc_entry);
 EXPORT_SYMBOL(proc_root);
 EXPORT_SYMBOL(proc_root_fs);
 EXPORT_SYMBOL(proc_get_inode);
-EXPORT_SYMBOL(in_group_p);
 EXPORT_SYMBOL(proc_dir_inode_operations);
 EXPORT_SYMBOL(proc_net_inode_operations);
 EXPORT_SYMBOL(proc_net);
index 2b438925a4fba46f59c4e6f3332886b2a1512e0f..cd434281c4b43d94cbc600bbae3729cecd9059d4 100644 (file)
@@ -254,10 +254,15 @@ static inline int buffer_protected(struct buffer_head * bh)
 /*
  * Deprecated - we don't keep per-buffer reference flags
  * any more.
+ *
+ * We _could_ try to update the page reference, but that
+ * doesn't seem to really be worth it either. If we did,
+ * it would look something like this:
+ *
+ *     #define buffer_page(bh)         (mem_map + MAP_NR((bh)->b_data))
+ *     #define touch_buffer(bh)        set_bit(PG_referenced, &buffer_page(bh)->flags)
  */
-#define buffer_page(bh)                (mem_map + MAP_NR((bh)->b_data))
-#define buffer_touched(bh)     (PageReferenced(buffer_page(bh)))
-#define touch_buffer(bh)       set_bit(PG_referenced, buffer_page(bh))
+#define touch_buffer(bh)       do { } while (0)
 
 #include <linux/pipe_fs_i.h>
 #include <linux/minix_fs_i.h>
index ad996ef84f3669c1bf9a33221947a6adb26dcfde..8038b4b98423d10bda8694899775dcf50a06d58d 100644 (file)
 #define PCI_DEVICE_ID_ADAPTEC2_2940U2  0x0010
 #define PCI_DEVICE_ID_ADAPTEC2_7890    0x001f
 #define PCI_DEVICE_ID_ADAPTEC2_3940U2  0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
 #define PCI_DEVICE_ID_ADAPTEC2_7896    0x005f
 
 #define PCI_VENDOR_ID_ATRONICS         0x907f
index c0bd15b486c8a77037602c8f8555a62b873bf21a..01f76c5c3f082f5728edda366bca896e070d92c8 100644 (file)
@@ -297,6 +297,8 @@ typedef     int (write_proc_t)(struct file *file, const char *buffer,
 extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
                                off_t offset, int length, int inout);
 
+#ifdef CONFIG_PROC_FS
+
 extern struct proc_dir_entry proc_root;
 extern struct proc_dir_entry proc_root_fs;
 extern struct proc_dir_entry *proc_net;
@@ -436,4 +438,26 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
  */
 extern void proc_device_tree_init(void);
 
+#else
+
+extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) {};
+extern inline int proc_unregister(struct proc_dir_entry *a, int b) {};
+extern inline int proc_net_register(struct proc_dir_entry *a) {};
+extern inline int proc_net_unregister(int x) {};
+extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) {};
+extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x);
+
+extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+                                        struct proc_dir_entry *parent)
+{
+       return NULL;
+}
+
+extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
+
+extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
+extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
+
+
+#endif
 #endif /* _LINUX_PROC_FS_H */
index c01ebfa4b8d96228ae66fab715169d53db4eec97..ef921caef4f308a22d2388acf904041e6f9affd5 100644 (file)
@@ -44,6 +44,7 @@ void                  rpc_proc_exit(void);
 void                   rpc_modcount(struct inode *, int);
 #endif
 
+#ifdef CONFIG_PROC_FS
 struct proc_dir_entry *        rpc_proc_register(struct rpc_stat *);
 void                   rpc_proc_unregister(const char *);
 int                    rpc_proc_read(char *, char **, off_t, int,
@@ -55,4 +56,18 @@ int                  svc_proc_read(char *, char **, off_t, int,
                                        int *, void *);
 void                   svc_proc_zero(struct svc_program *);
 
+#else
+
+extern inline void svc_proc_unregister(const char *p) {}
+extern inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
+{
+       return NULL;
+}
+
+extern inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
+{
+       return 0;
+}
+#endif
+
 #endif /* _LINUX_SUNRPC_STATS_H */
index 1b3bcbaa6eda4723286727870af9377869d2b57e..5fd67013ddd39ea9a41000b7407296d65f96cf29 100644 (file)
@@ -90,18 +90,6 @@ extern pager_daemon_t pager_daemon;
 #define PAGE_DECLINE           (swap_control.sc_page_decline)
 #define PAGE_INITIAL_AGE       (swap_control.sc_page_initial_age)
 
-/* Given a resource of N units (pages or buffers etc), we only try to
- * age and reclaim AGE_CLUSTER_FRACT per 1024 resources each time we
- * scan the resource list. */
-static inline int AGE_CLUSTER_SIZE(int resources)
-{
-       unsigned int n = (resources * AGE_CLUSTER_FRACT) >> 10;
-       if (n < AGE_CLUSTER_MIN)
-               return AGE_CLUSTER_MIN;
-       else
-               return n;
-}
-
 #endif /* __KERNEL */
 
 #endif /* _LINUX_SWAPCTL_H */
index 83d35f35d02b075f59605bc3caee8ca9a43d7fd0..dd8576b0cf5be2b54097d5b1f80edabfc85fc504 100644 (file)
@@ -12,7 +12,8 @@
 #include <linux/mm.h>
 #include <linux/shm.h>
 #include <linux/init.h>
-
+#include <linux/msg.h>
+#include <asm/ipc.h>
 #include <asm/uaccess.h>
 
 #if defined(CONFIG_SYSVIPC)
index 7c4edda2718333b91eac1eff97bc14750ea94164..8197368e3e14b975d98cc50302b057681a529c30 100644 (file)
@@ -151,6 +151,7 @@ void __free_page(struct page *page)
        if (!PageReserved(page) && atomic_dec_and_test(&page->count)) {
                if (PageSwapCache(page))
                        panic ("Freeing swap cache page");
+               page->flags &= ~(1 << PG_referenced);
                free_pages_ok(page->map_nr, 0);
                return;
        }
@@ -172,6 +173,7 @@ void free_pages(unsigned long addr, unsigned long order)
                if (atomic_dec_and_test(&map->count)) {
                        if (PageSwapCache(map))
                                panic ("Freeing swap cache pages");
+                       map->flags &= ~(1 << PG_referenced);
                        free_pages_ok(map_nr, order);
                        return;
                }
@@ -197,8 +199,9 @@ do { struct free_area_struct * area = free_area+order; \
        do { struct page *prev = memory_head(area), *ret = prev->next; \
                while (memory_head(area) != ret) { \
                        if (!dma || CAN_DMA(ret)) { \
-                               unsigned long map_nr = ret->map_nr; \
+                               unsigned long map_nr; \
                                (prev->next = ret->next)->prev = prev; \
+                               map_nr = ret->map_nr; \
                                MARK_USED(map_nr, new_order, area); \
                                nr_free_pages -= 1 << order; \
                                EXPAND(ret, map_nr, order, new_order, area); \
index cf7fa640f057f0850434c7e00b767e57f6bc1b4a..0536ff1ab41962f57c3f370624b64986e03c8d2e 100644 (file)
@@ -363,13 +363,23 @@ static int swap_out(unsigned int priority, int gfp_mask)
        /* 
         * We make one or two passes through the task list, indexed by 
         * assign = {0, 1}:
-        *   Pass 1: select the swappable task with maximal swap_cnt.
-        *   Pass 2: assign new swap_cnt values, then select as above.
+        *   Pass 1: select the swappable task with maximal RSS that has
+        *         not yet been swapped out. 
+        *   Pass 2: re-assign rss swap_cnt values, then select as above.
+        *
         * With this approach, there's no need to remember the last task
         * swapped out.  If the swap-out fails, we clear swap_cnt so the 
         * task won't be selected again until all others have been tried.
+        *
+        * Think of swap_cnt as a "shadow rss" - it tells us which process
+        * we want to page out (always try largest first).
         */
-       counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
+       counter = nr_tasks / (priority+1);
+       if (counter < 1)
+               counter = 1;
+       if (counter > nr_tasks)
+               counter = nr_tasks;
+
        for (; counter >= 0; counter--) {
                assign = 0;
                max_cnt = 0;
@@ -382,15 +392,9 @@ static int swap_out(unsigned int priority, int gfp_mask)
                                continue;
                        if (p->mm->rss <= 0)
                                continue;
-                       if (assign) {
-                               /* 
-                                * If we didn't select a task on pass 1, 
-                                * assign each task a new swap_cnt.
-                                * Normalise the number of pages swapped
-                                * by multiplying by (RSS / 1MB)
-                                */
-                               p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
-                       }
+                       /* Refresh swap_cnt? */
+                       if (assign)
+                               p->swap_cnt = p->mm->rss;
                        if (p->swap_cnt > max_cnt) {
                                max_cnt = p->swap_cnt;
                                pbest = p;
@@ -404,14 +408,13 @@ static int swap_out(unsigned int priority, int gfp_mask)
                        }
                        goto out;
                }
-               pbest->swap_cnt--;
 
                /*
                 * Nonzero means we cleared out something, but only "1" means
                 * that we actually free'd up a page as a result.
                 */
                if (swap_out_process(pbest, gfp_mask) == 1)
-                               return 1;
+                       return 1;
        }
 out:
        return 0;
@@ -451,19 +454,17 @@ static int kswapd_free_pages(int kswapd_state)
        /* max one hundreth of a second */
        end_time = jiffies + (HZ-1)/100;
        do {
-               int priority = 5;
+               int priority = 8;
                int count = pager_daemon.swap_cluster;
 
                switch (kswapd_state) {
                        do {
                        default:
                                free_memory(shrink_mmap(priority, 0));
+                               free_memory(swap_out(priority, 0));
                                kswapd_state++;
                        case 1:
                                free_memory(shm_swap(priority, 0));
-                               kswapd_state++;
-                       case 2:
-                               free_memory(swap_out(priority, 0));
                                shrink_dcache_memory(priority, 0);
                                kswapd_state = 0;
                        } while (--priority >= 0);
@@ -562,7 +563,7 @@ int try_to_free_pages(unsigned int gfp_mask, int count)
 
                current->flags |= PF_MEMALLOC;
        
-               priority = 5;
+               priority = 8;
                do {
                        free_memory(shrink_mmap(priority, gfp_mask));
                        free_memory(shm_swap(priority, gfp_mask));
index ff1dfd2dccbbca3aa744fa6773b7752c625da3aa..cd51ed9aad634c693dd8a779b3bb576b40909d86 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (C) 1996 Olaf Kirch, <okir@monad.swb.de>
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #define __KERNEL_SYSCALLS__
index 94a5ba21cbddd36298e67ef379f5ae2db6f422c3..2749eaac571b8c6e34c6c1fe95f3ea1ecb659568 100644 (file)
@@ -12,6 +12,7 @@
  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/kernel.h>
index a48e9c1adbef8882aeb91f532f03192622a017cc..5d70975ce8652eb900c55a2e1c80a659674118b8 100644 (file)
@@ -38,8 +38,10 @@ rpc_register_sysctl(void)
        if (!sunrpc_table_header) {
                sunrpc_table_header = register_sysctl_table(sunrpc_table, 1);
 #ifdef MODULE
+#ifdef CONFIG_PROC_FS
                if (sunrpc_table[0].de)
                        sunrpc_table[0].de->fill_inode = rpc_modcount;
+#endif
 #endif
        }
                        
index 028aede3db32b8d79ea186e4446421bea62ee8cb..0e0f3c7253e51aeec4798a888f1e51bd0b1f4b6e 100644 (file)
@@ -145,7 +145,7 @@ proc read_config_file { w } {
                         -relief raised 
                label $w.bm -bitmap error
                pack $w.bm $w.m -pady 10 -side top -padx 10
-               wm title $w "Oops
+               wm title $w "Xconfig Internal Error
 
                set oldFocus [focus]
                frame $w.f
@@ -173,7 +173,7 @@ proc write_config_file  { w } {
                         -relief raised 
                label $w.bm -bitmap error
                pack $w.bm $w.m -pady 10 -side top -padx 10
-               wm title $w "Oops
+               wm title $w "Xconfig Internal Error
 
                set oldFocus [focus]
                frame $w.f
diff --git a/scripts/ksymoops-0.6/Makefile b/scripts/ksymoops-0.6/Makefile
new file mode 100644 (file)
index 0000000..fa167b5
--- /dev/null
@@ -0,0 +1,72 @@
+# Description file for ksymoops
+
+#      Tue Nov  3 02:31:01 EST 1998
+#      Version 0.6
+#      Read lsmod (/proc/modules).
+#      Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
+#      Upper case variables.
+#      Convert from a.out to bfd, using same format as ksymoops.
+
+DEFS = Makefile ksymoops.h
+
+# Defaults for vmlinux, ksyms, objects, lsmod, System.map.  Externalised so
+# distributions can tweak to suit their own file system layout.
+
+# To default to not reading a source, set to any empty string.
+# To default to reading a source, supply a quoted and escaped string.
+
+# If the string contains *r (*m, *n, *s) then it is replaced at run time by
+# the current value of `uname -r` (-m, -n, -s).  '*' was chosen as something
+# that rarely appears in filenames and does not cause problems like '%' or '$'.
+
+DEF_VMLINUX =                          # default no vmlinux
+DEF_OBJECTS = \"/lib/modules/*r/\"     # default current modules
+DEF_KSYMS = \"/proc/ksyms\"            # default current ksyms
+DEF_LSMOD = \"/proc/modules\"          # default current lsmod
+DEF_MAP = \"/usr/src/linux/System.map\"        # default current map
+
+# RedHat users might want defaults like these
+# DEF_MAP = \"/boot/System.map-*r\"
+# DEF_OBJECTS = \"/boot/module-info-*r\"
+
+PROGS = ksymoops
+
+CC=gcc
+CFLAGS = -Dlinux \
+        -Wall \
+        -Wno-conversion \
+        -Waggregate-return \
+        -Wstrict-prototypes \
+        -Wmissing-prototypes \
+        $(DEBUG)
+
+ifneq ($(strip $(DEF_VMLINUX)),)
+       CFLAGS += -DDEF_VMLINUX=$(strip $(DEF_VMLINUX))
+endif
+ifneq ($(strip $(DEF_OBJECTS)),)
+       CFLAGS += -DDEF_OBJECTS=$(strip $(DEF_OBJECTS))
+endif
+ifneq ($(strip $(DEF_KSYMS)),)
+       CFLAGS += -DDEF_KSYMS=$(strip $(DEF_KSYMS))
+endif
+ifneq ($(strip $(DEF_LSMOD)),)
+       CFLAGS += -DDEF_LSMOD=$(strip $(DEF_LSMOD))
+endif
+ifneq ($(strip $(DEF_MAP)),)
+       CFLAGS += -DDEF_MAP=$(strip $(DEF_MAP))
+endif
+
+OBJECTS = io.o ksyms.o ksymoops.o map.o misc.o object.o oops.o re.o symbol.o
+
+all:   $(PROGS)
+
+:      $(OBJECTS)
+
+$(OBJECTS): $(DEFS)
+
+$(PROGS): %: %.o $(DEFS) $(OBJECTS)
+       $(CC) $(OBJECTS) $(CFLAGS) -lbfd -liberty -o $@
+       -@size $@
+
+clean:
+       rm -f core *.o $(PROGS)
diff --git a/scripts/ksymoops-0.6/README b/scripts/ksymoops-0.6/README
new file mode 100644 (file)
index 0000000..aef796b
--- /dev/null
@@ -0,0 +1,358 @@
+  ksymoops.
+
+  Read a kernel Oops file and make the best stab at converting the code to
+  instructions and mapping stack values to kernel symbols.
+
+  Copyright Keith Owens <kaos@ocs.com.au>.
+  Released under the GNU Public Licence, Version 2.
+
+  To compile, simply type "make" in the ksymoops directory.
+
+  TESTERS WANTED.
+
+  ksymoops handles ix86.  It appears to handle Alpha, Sparc, M68K, PPC,
+  MIPS but I have no machine to test on.  I would appreciate feedback
+  from users of non ix86 machines.  In particular, it would be nice if
+  you could run
+
+   ksymoops -VMO -k /proc/ksyms -dd <oops.file >/tmp/ksymoops.log 2>&1
+
+  and mail /tmp/ksymoops.log to kaos@ocs.com.au
+
+  The patches subdirectory contains some arch specific patches to
+  provide more info on their Oops reports.  At the moment (2.1.126),
+  some archs do not print traces or do not print code lines, makes it
+  impossible to report properly.
+
+  TODO:
+  Performance improvements.  Reading a large log is quite slow, probably
+         one of the Oops regular expressions is pathological.
+  Clean up these docs.
+  Add "guess", "same" options, distinguish between default and supplied
+  values on report (Andries, I get the message :).
+
+  Tue Nov  3 02:31:01 EST 1998
+  Version 0.6
+  Read lsmod (/proc/modules).
+
+  Wed Oct 28 23:14:55 EST 1998
+  Version 0.5
+  No longer read vmlinux by default, it only duplicates System.map.
+
+  Wed Oct 28 13:46:39 EST 1998
+  Version 0.4
+  Split into separate sources.
+
+  Mon Oct 26 00:01:47 EST 1998
+  Version 0.3c
+  Add alpha (arm) processing.
+
+  Mon Oct 26 00:01:47 EST 1998
+  Version 0.3b
+  Add sparc processing.
+  Handle kernel symbol versions.
+
+  Fri Oct 23 13:11:20 EST 1998
+  Version 0.3
+  Add -follow to find command for people who use symlinks to modules.
+  Add Version_ checking.
+
+  Thu Oct 22 22:28:30 EST 1998
+  Version 0.2.
+  Generalise text prefix handling.
+  Handle messages on Code: line.
+  Format addresses with leading zeroes.
+  Minor bug fixes.
+
+  Wed Oct 21 23:28:48 EST 1998
+  Version 0.1.  Rewrite from scratch in C.
+
+  CREDITS.
+  Oops disassembly based on ksymoops.cc,
+    Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
+  m68k code based on ksymoops.cc changes by
+    Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+  This code subsumes the Perl script make_System.map.pl which is no longer
+  supported.
+
+  Why another ksymoops I hear you ask?  Various complaints about
+  ksymoops.cc -
+
+  * It requires C++.
+  * It has hard wired limitations on the number of symbols.
+  * It does not handle modules at all.
+  * Very rigid requirements on the format of input, especially the Oops
+    log.
+  * No cross checking between ksyms, modules, System.map etc.
+  * Very little error checking, diagnostics are not suitable for
+    beginners.
+  * It only prints the trace and decoded code, users have to manually
+    extract the other lines from the Oops.
+  * Gives up on the slightest problem.
+  * Only handles i386 and possibly m68k.  The code is difficult to extend
+    to other architectures.
+  * Stops after the first Oops, you have to manually extract each one and
+    run through ksymoops one at a time.
+
+  This version is -
+  * C.
+  * No hard wired limitations (malloc as far as the eye can see).
+  * Handles modules by default.
+  * Uses regular pattern matching so it is a lot more forgiving about
+    input formats.
+  * By default, cross checks ksyms, modules, System.map and vmlinux.
+  * Lots of diagnostics and error checking.
+  * Prints all relevant lines for a complete Oops report.
+  * Tries to provide output no matter how bad the input is.  The level of
+     progress and error reporting is aimed at beginners.
+  * Handles i386, alpha, sparc, m68k.  It is a lot easier to extend to
+    other architectures (patches and/or sample data gratefully accepted).
+  * Handles all Oops in the input file(s).
+
+
+  Usage:       ksymoops
+                 [-v vmlinux]  Where to read vmlinux
+                 [-V]          No vmlinux is available
+                 [-o object_dir]       Directory containing modules
+                 [-O]          No modules is available
+                 [-k ksyms]    Where to read ksyms
+                 [-K]          No ksyms is available
+                 [-l lsmod]    Where to read lsmod
+                 [-L]          No lsmod is available
+                 [-m system.map]       Where to read System.map
+                 [-M]          No System.map is available
+                 [-s save.map] Save consolidated map
+                 [-d]          Increase debug level by 1
+                 [-h]          Print help text
+                 Oops.file     Oops to decode
+
+         All flags can occur more than once.  With the exception of -o
+         and -d which are cumulative, the last occurrence of each flag is
+         used.  Note that "-v my.vmlinux -V" will be taken as "No vmlinux
+         available" but "-V -v my.vmlinux" will read my.vmlinux.  You
+         will be warned about such combinations.
+
+         Each occurrence of -d increases the debug level.
+
+         Each -o flag can refer to a directory or to a single object
+         file.  If a directory is specified then all *.o files in that
+         directory and its subdirectories are assumed to be modules.
+
+         If any of the vmlinux, object_dir, ksyms or system.map options
+         contain the string *r (*m, *n, *s) then it is replaced at run time
+         by the current value of `uname -r` (-m, -n, -s).
+
+         The defaults can be changed in the Makefile, typical options are
+
+         Defaults:       -V
+                         -o /lib/modules/%r
+                         -k /proc/ksyms
+                         -l /proc/modules
+                         -m /usr/src/linux/System.map
+                         Oops report is read from stdin
+
+  Note:          Unless you tell ksymoops *NOT* to read a particular file, it
+         will try to read and reconcile almost all possible sources of kernel
+         symbol information.  This is intended for beginners, they just
+         type
+
+           ksymoops < /var/log/syslog
+
+         no thinking required.  Experts can point at different files or
+         suppress the input from selected files.  For example, if you
+         save /proc/ksyms before doing a test that creates an Oops, you
+         can point ksymoops at the saved ksyms instead of using
+         /proc/ksyms.
+
+         vmlinux is not read by default, it only duplicates the
+         information in System.map.  If you want to read vmlinux as well
+         as or instead of System.map, use -v.
+
+         To get the equivalent of the old ksymoops.cc (no vmlinux, no
+         modules objects, no ksyms, no System.map) just do ksymoops
+         -VOKLM.  Or to just read System.map, ksymoops -VOKL -m mapfile.
+
+
+  WARNING:  The user interface will change slightly in 0.7, users will
+            have to give some indication of the state of their
+            environment.  Otherwise it may be too easy to pick the
+            wrong input files.
+
+  Return codes:        0 - normal.
+                 1 - error(s) or warning(s) issued, results may not be
+                     reliable.
+                 2 - fatal error, no useful results.
+
+  Supported architectures
+
+         i386 tested.
+          m68k code derived from ksymoops.cc and reading traps.c, untested.
+         MIPS tested.
+         Sparc tested.
+         Alpha tested.
+
+         The term "eip" is generic, for example it includes the i386 EIP
+         and the m68k PC.  Remember that objdump output always says EIP,
+         no matter what the architecture, see objfile_head.
+
+         To support another arch, check the Oops_ procedures between
+         'Start architecture sensitive code' and 'End architecture
+         sensitive code'.
+
+         The pattern matching should take care of different lengths for
+         the address, i.e. addresses should not be arch sensitive.  I
+         assume that all addresses are at least 4 characters.
+
+         If nm output has a different format on your arch, check for uses
+         of re_nm.
+
+
+
+  Because ksymoops reads kernel information from multiple sources, there
+  could be mismatches.  ksymoops does the following cross checks, but only
+  if the specified files exist -
+
+  * Compare Version_nnn numbers from all sources against each other.  Pity
+    that only vmlinux and System.map have these symbols (as at 2.1.125),
+    however I check ksyms, modules and Oops as well.  If somebody adds
+    symbol Version_nnn to ksyms or modules or adds a Version_nnn line to
+    the Oops log, this code is ready.
+
+  * Compare kernel ksyms against vmlinux.  vmlinux takes precedence.
+
+  * Compare System.map against vmlinux.   vmlinux takes precedence.
+
+  * Compare vmlinux against System.map.   vmlinux takes precedence.
+
+  * Compare kernel ksyms against System.map.  System.map takes precedence.
+
+  * Compare modules against module ksyms.  modules take precedence.  Only
+    if at least one module appears in ksyms.
+
+  * Compare module names in ksyms against lsmod.  Warn if a module
+    appears in lsmod but not in ksyms.  Error if a modules appears in
+    ksyms but is not in lsmod.  Only if both ksyms and lsmod have being
+    read.
+
+  The precedence order is somewhat arbitrary, however it only applies if
+  there is any difference between the various sources.
+
+  Handling modules is awkward.  They can be loaded under different names
+  (insmod -o dummy1 dummy.o) and the text, data and read only data are
+  loaded at different offsets.  Although you can give the -m option to
+  insmod which will output the module map when it is loaded, this has a
+  few problems -
+
+  * No equivalent for removing a module.  If you load and remove a lot of
+    modules, you end up with multiple sets of symbols around the same
+    offsets, which set is correct?
+
+  * "insmod -o dummy1 dummy.o" still reports as dummy.  That is, there is
+     no way of telling which particular version of a multiply loaded
+     module the insmod output refers to.  Therefore there is no way of
+     telling which instantiation failed.
+
+  * Even if the above problems are fixed, how do you tell what the module
+    environment looked like when the Oops occurred?  What if a module is
+    loaded or removed just after Oops, how is the user expected to edit
+    the insmod log?  Rule 1 - make ksymoops easy for beginners.
+
+  Although those problems could be fixed, they require changes to
+  modutils.  Working from ksyms and the module objects can be done without
+  changing modutils and without confusing beginners.
+  
+  Alas the ksyms plus object approach has another problem - matching ksyms
+  to module objects.  Nowhere does the kernel say that module dummy1 came
+  from module /lib/modules/2.1.215/net/dummy.o, ksyms just says dummy1.  I
+  have to match ksyms to the relevant object by finding a globally unique
+  external symbol in each module that can be used to map to the external
+  symbols in ksyms.  This assumes that each module exports at least one
+  text symbol that is unique amongst all modules.
+
+  It may not be possible to correctly map other sections such as data and
+  readonly data for modules because they may not have exported symbols.
+  Since the main aim of ksymoops is to map a code Oops, this should not be
+  a problem.
+
+  Unfortunately some modules export no symbols.  They are marked as
+  EXPORT_NO_SYMBOLS are simply do not export anything.  It is
+  impossible to detect these in ksyms because, by definition, ksyms
+  only contains exported symbols for modules.  Since all modules appear
+  in lsmod (/proc/modules), a cross check of lsmod against the module
+  names will find loaded modules with no symbols, at least I can warn
+  about these.
+
+  After merging the various sources, ksymoops has a (hopefully) accurate
+  map including modules.  The -s option lets you save the merged
+  System.map, but remember that module data and readonly data sections may
+  not be correctly relocated, see above.
+
+  Environment Variables.
+  KSYMOOPS_NM          path for nm, defaults to /usr/bin/nm.
+  KSYMOOPS_FIND                path for find, defaults to /usr/bin/find.
+  KSYMOOPS_OBJDUMP     path for objdump, defaults to /usr/bin/objdump.
+
+
+  Input Oops data.
+
+  The ideal input is to feed the syslog straight into this program.  If
+  you cannot do that, you need to know what the program looks for.
+  Especially if you are typing in the Oops by hand :(.  All input is case
+  insensitive.
+
+  * White space in this context means space or tab.  It does not include
+    newline.
+
+  * Oops in syslog has a syslog prefix.  Leading text up to and including
+    ' kernel: ' is always ignored, there is no need to edit syslog first.
+    This leading text need not exist but if it does, it must end in
+    ' kernel: '.
+
+  * An alternative prefix is <n> where n is the kernel print level.  Also
+    ignored if present.
+
+  * Leading white space is treated as a prefix and ignored, the input is
+    not indentation sensitive.
+
+  * In the following paragraphs, assume that any prefixes have been
+    skipped.  If there is more than one prefix, all are skipped, no matter
+    which order they appear in.
+
+  * A bracketed address is optional '[', required '<', at least 4 hex
+    digits, required '>', optional ']'.  For example [<01234567>] or
+    <1234>.
+
+  * The ix86 EIP line is identified by optional white space followed by
+    'EIP:', followed by a least one white space, followed by a bracketed
+    address.
+
+  * The m68k PC line is identified by optional white space followed by
+    'PC', optionally followed by white space, followed by '=', optionally
+    followed by white space, followed by a bracketed address.
+
+  * The sparc PC line starts with PSR and PC is the second hex value, not
+    bracketed.
+
+  * A call trace line is identified by 'Call Trace:' followed by at least
+    one white space.  Or it is a line starting with a bracketed address,
+    but only if the previous line was a call trace line (I hate multi line
+    output that relies on identation for recognition, especially when
+    lines can have a variable prefix).
+
+  * The Code line is identified by 'Code:' followed by a least one white
+    space character followed by at least one hex value.  The line can
+    contain multiple hex values, each separated by at least one white
+    space.  Each hex value must be 2 to 8 digits and must be a multiple of
+    2 digits.
+
+    Special cases where Code: can be followed by text.
+      'Code: general protection'
+      'Code: <n>'
+    Dump the data anyway, the code was unavailable.
+
+  * Formatted data is only output when the Code: line is seen.  If any
+    data has been stored and more than 5 lines other than Oops text (see
+    Oops_print) or end of file are encountered then ksymoops assumes that
+    the Code: line is missing or garbled and dumps the formatted data
+    anyway.  Fail safe, I hope.
diff --git a/scripts/ksymoops-0.6/io.c b/scripts/ksymoops-0.6/io.c
new file mode 100644 (file)
index 0000000..b54e8ad
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+       io.c.
+
+       Local I/O routines for ksymoops.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       fwrite_local is redundant, replaced by bfd.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+
+ */
+
+#include "ksymoops.h"
+#include <errno.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/stat.h>
+
+int regular_file(const char *file, const char *msg)
+{
+       struct stat statbuf;
+       if (stat(file, &statbuf)) {
+               fprintf(stderr, "%s: %s stat %s failed",
+                       prefix, msg, file);
+               perror(" ");
+               ++errors;
+               return 0;
+       }
+
+       if (!S_ISREG(statbuf.st_mode)) {
+               fprintf(stderr,
+                       "%s: %s %s is not a regular file, ignored\n",
+                       prefix, msg, file);
+               ++errors;
+               return 0;
+       }
+       return 1;
+}
+
+FILE *fopen_local(const char *file, const char *mode, const char *msg)
+{
+       FILE *f;
+       if (!(f = fopen(file, mode))) {
+               fprintf(stderr, "%s: %s fopen '%s' failed",
+                       prefix, msg, file);
+               perror(" ");
+               ++errors;
+       }
+       return f;
+}
+
+void fclose_local(FILE *f, const char *msg)
+{
+       int i;
+       if ((i = fclose(f))) {
+               fprintf(stderr, "%s: %s fclose failed %d", prefix, msg, i);
+               perror(" ");
+               ++errors;
+       }
+}
+
+/* Read a line, increasing the size of the line as necessary until \n is read */
+#define INCREMENT 10   /* arbitrary */
+char *fgets_local(char **line, int *size, FILE *f, const char *msg)
+{
+       char *l, *p, *r;
+       int longline = 1;
+
+       if (!*line) {
+               *size = INCREMENT;
+               *line = malloc(*size);
+               if (!*line)
+                       malloc_error("fgets_local alloc line");
+       }
+
+       l = *line;
+       while (longline) {
+               r = fgets(l, *size-(l-*line), f);
+               if (!r) {
+                       if (ferror(f)) {
+                               fprintf(stderr,
+                                       "%s: %s fgets failed", prefix, msg);
+                               perror(" ");
+                               ++errors;
+                       }
+                       if (l != *line)
+                               return(*line);
+                       else
+                               return(r);
+               }
+               if (!(p = strchr(*line, '\n'))) {
+                       *size += INCREMENT;
+                       *line = realloc(*line, *size);
+                       if (!*line)
+                               malloc_error("fgets_local realloc line");
+                       l = *line+*size-INCREMENT-1;
+               }
+               else {
+                       *p = '\0';
+                       longline = 0;
+               }
+       }
+
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s line '%s'\n", msg, *line);
+       return(*line);
+}
+
+FILE *popen_local(const char *cmd, const char *msg)
+{
+       FILE *f;
+       if (!(f = popen(cmd, "r"))) {
+               fprintf(stderr, "%s: %s popen '%s' failed",
+                       prefix, msg, cmd);
+               perror(" ");
+               ++errors;
+       }
+       return f;
+}
+
+void pclose_local(FILE *f, const char *msg)
+{
+       int i;
+       errno = 0;
+       if ((i = pclose(f))) {
+               fprintf(stderr, "%s: %s pclose failed 0x%x", prefix, msg, i);
+               if (errno)
+                       perror(" ");
+               else
+                       fprintf(stderr, "\n");
+               ++errors;
+       }
+}
diff --git a/scripts/ksymoops-0.6/ksymoops.c b/scripts/ksymoops-0.6/ksymoops.c
new file mode 100644 (file)
index 0000000..78be43b
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+       ksymoops.c.
+
+       Read a kernel Oops file and make the best stab at converting the code to
+       instructions and mapping stack values to kernel symbols.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+*/
+
+#define VERSION "0.6"
+
+/*
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Read lsmod (/proc/modules).
+       Ignore addresses 0-4095 when mapping address to symbol.
+       Discard default objects if -o specified.
+       Oops file must be regular.
+       Add "invalid operand" to Oops_print.
+       Move "Using_Version" copy to map.c.
+       Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
+       Minor adjustment to re for ppc.
+       Minor adjustment to re for objdump lines with <_EIP+xxx>.
+       Convert from a.out to bfd, using same format as ksymoops.
+       Added MIPS.
+       PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
+
+       Wed Oct 28 23:14:55 EST 1998
+       Version 0.5
+       No longer read vmlinux by default, it only duplicates System.map.
+
+       Wed Oct 28 13:47:38 EST 1998
+       Version 0.4
+       Split into separate sources.
+
+       Mon Oct 26 00:01:47 EST 1998
+       Version 0.3c
+       Add alpha (arm) processing.
+
+       Mon Oct 26 00:01:47 EST 1998
+       Version 0.3b
+       Add sparc processing.
+       Handle kernel symbol versions.
+
+       Fri Oct 23 13:11:20 EST 1998
+       Version 0.3
+       Add -follow to find command for people who use symlinks to modules.
+       Add Version_ checking.
+
+       Thu Oct 22 22:28:30 EST 1998
+       Version 0.2.
+       Generalise text prefix handling.
+       Handle messages on Code: line.
+       Format addresses with leading zeroes.
+       Minor bug fixes.
+
+       Wed Oct 21 23:28:48 EST 1998
+       Version 0.1.  Rewrite from scratch in C.
+
+       CREDITS.
+       Oops disassembly based on ksymoops.cc,
+         Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
+       m68k code based on ksymoops.cc changes by
+         Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ */
+
+#include "ksymoops.h"
+#include <ctype.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+char *prefix;
+char *path_nm = "/usr/bin/nm";                 /* env KSYMOOPS_NM */
+char *path_find = "/usr/bin/find";             /* env KSYMOOPS_FIND */
+char *path_objdump = "/usr/bin/objdump";       /* env KSYMOOPS_OBJDUMP */
+int debug = 0;
+int errors = 0;
+int warnings = 0;
+
+SYMBOL_SET  ss_vmlinux;
+SYMBOL_SET  ss_ksyms_base;
+SYMBOL_SET *ss_ksyms_module;
+int         ss_ksyms_modules;
+SYMBOL_SET  ss_lsmod;
+SYMBOL_SET *ss_object;
+int         ss_objects;
+SYMBOL_SET  ss_system_map;
+
+SYMBOL_SET  ss_merged;   /* merged map with info from all sources */
+SYMBOL_SET  ss_Version;  /* Version_ numbers where available */
+
+/* Regular expression stuff */
+
+regex_t     re_nm;
+regmatch_t *re_nm_pmatch;
+regex_t     re_bracketed_address;
+regmatch_t *re_bracketed_address_pmatch;
+regex_t     re_unbracketed_address;
+regmatch_t *re_unbracketed_address_pmatch;
+
+static void usage(void)
+{
+       fprintf(stderr, "Version " VERSION "\n");
+       fprintf(stderr, "usage: %s\n", prefix);
+       fprintf(stderr,
+               "\t\t[-v vmlinux]\tWhere to read vmlinux\n"
+               "\t\t[-V]\t\tNo vmlinux is available\n"
+               "\t\t[-o object_dir]\tDirectory containing modules\n"
+               "\t\t[-O]\t\tNo modules is available\n"
+               "\t\t[-k ksyms]\tWhere to read ksyms\n"
+               "\t\t[-K]\t\tNo ksyms is available\n"
+               "\t\t[-l lsmod]\tWhere to read lsmod\n"
+               "\t\t[-L]\t\tNo lsmod is available\n"
+               "\t\t[-m system.map]\tWhere to read System.map\n"
+               "\t\t[-M]\t\tNo System.map is available\n"
+               "\t\t[-s save.map]\tSave consolidated map\n"
+               "\t\t[-d]\t\tIncrease debug level by 1\n"
+               "\t\t[-h]\t\tPrint help text\n"
+               "\t\t<Oops.file\tOops report to decode\n"
+               "\n"
+               "\t\tAll flags can occur more than once.  With the exception "
+                       "of -o\n"
+               "\t\tand -d which are cumulative, the last occurrence of each "
+                       "flag is\n"
+               "\t\tused.  Note that \"-v my.vmlinux -V\" will be taken as "
+                       "\"No vmlinux\n"
+               "\t\tavailable\" but \"-V -v my.vmlinux\" will read "
+                       "my.vmlinux.  You\n"
+               "\t\twill be warned about such combinations.\n"
+               "\n"
+               "\t\tEach occurrence of -d increases the debug level.\n"
+               "\n"
+               "\t\tEach -o flag can refer to a directory or to a single "
+                       "object\n"
+               "\t\tfile.  If a directory is specified then all *.o files in "
+                       "that\n"
+               "\t\tdirectory and its subdirectories are assumed to be "
+                       "modules.\n"
+               "\n"
+               "\t\tIf any of the vmlinux, object_dir, ksyms or system.map "
+               "options\n"
+               "\t\tcontain the string *r (*m, *n, *s) then it is replaced "
+               "at run\n"
+               "\t\ttime by the current value of `uname -r` (-m, -n, -s).\n"
+               "\n"
+               "\t\tThe defaults can be changed in the Makefile, current "
+               "defaults\n"
+               "\t\tare\n\n"
+               "\t\t\t"
+#ifdef DEF_VMLINUX
+               "-v " DEF_LINUX
+#else
+               "-V"
+#endif
+               "\n"
+               "\t\t\t"
+#ifdef DEF_OBJECTS
+               "-o " DEF_OBJECTS
+#else
+               "-O"
+#endif
+               "\n"
+               "\t\t\t"
+#ifdef DEF_KSYMS
+               "-k " DEF_KSYMS
+#else
+               "-K"
+#endif
+               "\n"
+               "\t\t\t"
+#ifdef DEF_LSMOD
+               "-l " DEF_LSMOD
+#else
+               "-L"
+#endif
+               "\n"
+               "\t\t\t"
+#ifdef DEF_MAP
+               "-m " DEF_MAP
+#else
+               "-M"
+#endif
+               "\n"
+               "\t\t\tOops report is read from stdin\n"
+               "\n"
+              );
+}
+
+/* Check if possibly conflicting options were specified */
+static void multi_opt(int specl, int specu, char type, const char *using)
+{
+       if (specl && specu) {
+               fprintf(stderr,
+                       "Warning - you specified both -%c and -%c.  Using '",
+                       type, toupper(type));
+               ++warnings;
+               if (using) {
+                       fprintf(stderr, "-%c %s", type, using);
+                       if (type == 'o')
+                               fprintf(stderr, " ...");
+                       fprintf(stderr, "'\n");
+               }
+               else
+                       fprintf(stderr, "-%c'\n", toupper(type));
+       }
+       else if (specl > 1 && type != 'o') {
+               fprintf(stderr,
+                       "Warning - you specified -%c more than once.  "
+                       "Using '-%c %s'\n",
+                       type, type, using);
+               ++warnings;
+       }
+       else if (specu > 1) {
+               fprintf(stderr,
+                       "Warning - you specified -%c more than once.  "
+                       "Second and subsequent '-%c' ignored\n",
+                       toupper(type), toupper(type));
+               ++warnings;
+       }
+}
+
+/* If a name contains *r (*m, *n, *s), replace with the current value of
+ * `uname -r` (-m, -n, -s).  Actually uses uname system call rather than the
+ * uname command but the result is the same.
+ */
+static void convert_uname(char **name)
+{
+       char *p, *newname, *oldname, *replacement;
+       unsigned len;
+       int free_oldname = 0;
+       static char procname[] = "convert_uname";
+
+       if (!*name)
+               return;
+
+       while ((p = strchr(*name, '*'))) {
+               struct utsname buf;
+               int i = uname(&buf);
+               if (debug)
+                       fprintf(stderr, "DEBUG: %s %s in\n", procname, *name);
+               if (i) {
+                       fprintf(stderr,
+                               "%s: uname failed, %s will not be processed\n",
+                               prefix, *name);
+                       perror(prefix);
+                       ++errors;
+                       return;
+               }
+               switch (*(p+1)) {
+               case 'r':
+                       replacement = buf.release;
+                       break;
+               case 'm':
+                       replacement = buf.machine;
+                       break;
+               case 'n':
+                       replacement = buf.nodename;
+                       break;
+               case 's':
+                       replacement = buf.sysname;
+                       break;
+               default:
+                       fprintf(stderr,
+                               "%s: invalid replacement character '*%c' "
+                               "in %s\n",
+                               prefix, *(p+1), *name);
+                       ++errors;
+                       return;
+               }
+               len = strlen(*name)-2+strlen(replacement)+1;
+               if (!(newname = malloc(len)))
+                       malloc_error(procname);
+               strncpy(newname, *name, (p-*name));
+               strcpy(newname+(p-*name), replacement);
+               strcpy(newname+(p-*name)+strlen(replacement), p+2);
+               p = newname+(p-*name)+strlen(replacement);      /* no rescan */
+               oldname = *name;
+               *name = newname;
+               if (free_oldname)
+                       free(oldname);
+               free_oldname = 1;
+               if (debug)
+                       fprintf(stderr, "DEBUG: %s %s out\n", procname, *name);
+       }
+       return;
+}
+
+/* Parse the options.  Verbose but what's new with getopt? */
+static void parse(int argc,
+                 char **argv,
+                 char **vmlinux,
+                 char ***object,
+                 int *objects,
+                 char **ksyms,
+                 char **lsmod,
+                 char **system_map,
+                 char **save_system_map,
+                 char ***filename,
+                 int *filecount,
+                 int *spec_h
+                )
+{
+       int spec_v = 0, spec_V = 0;
+       int spec_o = 0, spec_O = 0;
+       int spec_k = 0, spec_K = 0;
+       int spec_l = 0, spec_L = 0;
+       int spec_m = 0, spec_M = 0;
+       int spec_s = 0;
+
+       int c, i;
+       char *p;
+
+       while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dh")) != EOF) {
+               if (debug && c != 'd')
+                       fprintf(stderr, "DEBUG: getopt '%c' '%s'\n", c, optarg);
+               switch(c) {
+               case 'v':
+                       *vmlinux = optarg;
+                       ++spec_v;
+                       break;
+               case 'V':
+                       *vmlinux = NULL;
+                       ++spec_V;
+                       break;
+               case 'o':
+                       if (!spec_o) {
+                               /* First -o, discard default value(s) */
+                               for (i = 0; i < *objects; ++i)
+                                       free((*object)[i]);
+                               free(*object);
+                               *object = NULL;
+                               *objects = 0;
+                       }
+                       *object = realloc(*object,
+                               ((*objects)+1)*sizeof(**object));
+                       if (!*object)
+                               malloc_error("object");
+                       if (!(p = strdup(optarg)))
+                               malloc_error("strdup -o");
+                       else {
+                               (*object)[(*objects)++] = p;
+                               ++spec_o;
+                       }
+                       break;
+               case 'O':
+                       ++spec_O;
+                       for (i = 0; i < *objects; ++i)
+                               free((*object)[i]);
+                       free(*object);
+                       *object = NULL;
+                       *objects = 0;
+                       break;
+               case 'k':
+                       *ksyms = optarg;
+                       ++spec_k;
+                       break;
+               case 'K':
+                       *ksyms = NULL;
+                       ++spec_K;
+                       break;
+               case 'l':
+                       *lsmod = optarg;
+                       ++spec_l;
+                       break;
+               case 'L':
+                       *lsmod = NULL;
+                       ++spec_L;
+                       break;
+               case 'm':
+                       *system_map = optarg;
+                       ++spec_m;
+                       break;
+               case 'M':
+                       *system_map = NULL;
+                       ++spec_M;
+                       break;
+               case 's':
+                       *save_system_map = optarg;
+                       ++spec_s;
+                       break;
+               case 'd':
+                       ++debug;
+                       break;
+               case 'h':
+                       usage();
+                       ++*spec_h;
+                       break;
+               case '?':
+                       usage();
+                       exit(2);
+               }
+       }
+
+       *filecount = argc - optind;
+       *filename = argv + optind;
+
+       /* Expand any requests for the current uname values */
+       convert_uname(vmlinux);
+       if (*objects) {
+               for (i = 0; i < *objects; ++i)
+                       convert_uname(*object+i);
+       }
+       convert_uname(ksyms);
+       convert_uname(lsmod);
+       convert_uname(system_map);
+
+       /* Check for multiple options specified */
+       multi_opt(spec_v, spec_V, 'v', *vmlinux);
+       multi_opt(spec_o, spec_O, 'o', *object ? **object : NULL);
+       multi_opt(spec_k, spec_K, 'k', *ksyms);
+       multi_opt(spec_l, spec_L, 'l', *lsmod);
+       multi_opt(spec_m, spec_M, 'm', *system_map);
+
+       printf("Options used:");
+       if (*vmlinux)
+               printf(" -v %s", *vmlinux);
+       else
+               printf(" -V");
+       if (*objects) {
+               for (i = 0; i < *objects; ++i)
+                       printf(" -o %s", (*object)[i]);
+       }
+       else
+               printf(" -O");
+       if (*ksyms)
+               printf(" -k %s", *ksyms);
+       else
+               printf(" -K");
+       if (*lsmod)
+               printf(" -l %s", *lsmod);
+       else
+               printf(" -L");
+       if (*system_map)
+               printf(" -m %s", *system_map);
+       else
+               printf(" -M");
+       printf("\n\n");
+}
+
+/* Read environment variables */
+static void read_env(const char *external, char **internal)
+{
+       char *p;
+       if ((p = getenv(external))) {
+               *internal = p;
+               if (debug)
+                       fprintf(stderr,
+                               "DEBUG: env override %s=%s\n",
+                               external, *internal);
+       }
+       else {
+               if (debug)
+                       fprintf(stderr,
+                               "DEBUG: env default %s=%s\n",
+                               external, *internal);
+       }
+}
+
+
+int main(int argc, char **argv)
+{
+       char *vmlinux = NULL;
+       char **object = NULL;
+       int objects = 0;
+       char *ksyms = NULL;
+       char *lsmod = NULL;
+       char *system_map = NULL;
+       char *save_system_map = NULL;
+       char **filename;
+       int filecount = 0;
+       int spec_h = 0;         /* -h was specified */
+       int i;
+
+       prefix = *argv;
+       setvbuf(stdout, NULL, _IONBF, 0);
+
+#ifdef DEF_VMLINUX
+       vmlinux = DEF_LINUX;
+#endif
+#ifdef DEF_OBJECTS
+       {
+               char *p;
+               object = realloc(object, (objects+1)*sizeof(*object));
+               if (!object)
+                       malloc_error("DEF_OBJECTS");
+               if (!(p = strdup(DEF_OBJECTS)))
+                       malloc_error("DEF_OBJECTS");
+               else
+                       object[objects++] = p;
+       }
+#endif
+#ifdef DEF_KSYMS
+       ksyms = DEF_KSYMS;
+#endif
+#ifdef DEF_LSMOD
+       lsmod = DEF_LSMOD;
+#endif
+#ifdef DEF_MAP
+       system_map = DEF_MAP;
+#endif
+
+       parse(argc,
+             argv,
+             &vmlinux,
+             &object,
+             &objects,
+             &ksyms,
+             &lsmod,
+             &system_map,
+             &save_system_map,
+             &filename,
+             &filecount,
+             &spec_h
+            );
+
+       if (spec_h && filecount == 0)
+               return(0);      /* just the help text */
+
+       if (debug)
+               fprintf(stderr, "DEBUG: level %d\n", debug);
+
+       read_env("KSYMOOPS_NM", &path_nm);
+       read_env("KSYMOOPS_FIND", &path_find);
+       read_env("KSYMOOPS_OBJDUMP", &path_objdump);
+
+       re_compile_common();
+       ss_init_common();
+
+       read_vmlinux(vmlinux);
+       read_ksyms(ksyms);
+       /* No point in reading modules unless ksyms shows modules loaded */
+       if (ss_ksyms_modules) {
+               expand_objects(object, objects);
+               for (i = 0; i < ss_objects; ++i)
+                       read_object(ss_object[i].source, i);
+       }
+       else if (objects)
+               printf("No modules in ksyms, skipping objects\n");
+       /* No point in reading lsmod without ksyms */
+       if (ss_ksyms_modules || ss_ksyms_base.used)
+               read_lsmod(lsmod);
+       else if (lsmod)
+               printf("No ksyms, skipping lsmod\n");
+       read_system_map(system_map);
+       merge_maps(save_system_map);
+
+       /* After all that work, it is finally time to read the Oops report */
+       Oops_read(filecount, filename);
+
+       if (warnings || errors) {
+               printf("\n");
+               if (warnings)
+                       printf("%d warning%s ",
+                              warnings, warnings == 1 ? "" : "s");
+               if (warnings && errors)
+                       printf("and ");
+               if (errors)
+                       printf("%d error%s ", errors, errors == 1 ? "" : "s");
+               printf("issued.  Results may not be reliable.\n");
+               return(1);
+       }
+
+       return(0);
+}
diff --git a/scripts/ksymoops-0.6/ksymoops.h b/scripts/ksymoops-0.6/ksymoops.h
new file mode 100644 (file)
index 0000000..88aa0a7
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+       ksymoops.h.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Read lsmod (/proc/modules).
+       Convert from a.out to bfd, using same format as ksymoops.
+       PPC trace addresses are not bracketed, add new re.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+*/
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+
+
+/* Pity this is not externalised, see binfmt_elf.c */
+#define elf_addr_t unsigned long
+
+extern char *prefix;
+extern char *path_nm;          /* env KSYMOOPS_NM */
+extern char *path_find;                /* env KSYMOOPS_FIND */
+extern char *path_objdump;     /* env KSYMOOPS_OBJDUMP */
+extern int debug;
+extern int errors;
+extern int warnings;
+
+typedef struct symbol SYMBOL;
+
+struct symbol {
+       char *name;             /* name of symbol */
+       char type;              /* type of symbol from nm/System.map */
+       char keep;              /* keep this symbol in merged map? */
+       elf_addr_t address;     /* address in kernel */
+};
+
+/* Header for symbols from one particular source */
+
+typedef struct symbol_set SYMBOL_SET;
+
+struct symbol_set {
+       char *source;                   /* where the symbols came from */
+       int used;                       /* number of symbols used */
+       int alloc;                      /* number of symbols allocated */
+       SYMBOL *symbol;                 /* dynamic array of symbols */
+       SYMBOL_SET *related;            /* any related symbol set */
+};
+
+extern SYMBOL_SET  ss_vmlinux;
+extern SYMBOL_SET  ss_ksyms_base;
+extern SYMBOL_SET *ss_ksyms_module;
+extern int         ss_ksyms_modules;
+extern SYMBOL_SET  ss_lsmod;
+extern SYMBOL_SET *ss_object;
+extern int         ss_objects;
+extern SYMBOL_SET  ss_system_map;
+
+extern SYMBOL_SET  ss_merged;  /* merged map with info from all sources */
+extern SYMBOL_SET  ss_Version; /* Version_ numbers where available */
+
+/* Regular expression stuff */
+
+extern regex_t     re_nm;
+extern regmatch_t *re_nm_pmatch;
+extern regex_t     re_bracketed_address;
+extern regmatch_t *re_bracketed_address_pmatch;
+extern regex_t     re_unbracketed_address;
+extern regmatch_t *re_unbracketed_address_pmatch;
+
+/* Bracketed address: optional '[', required '<', at least 4 hex characters,
+ * required '>', optional ']', optional white space.
+ */
+#define BRACKETED_ADDRESS      "\\[*<([0-9a-fA-F]{4,})>\\]*[ \t]*"
+
+#define UNBRACKETED_ADDRESS    "([0-9a-fA-F]{4,})[ \t]*"
+
+/* io.c */
+extern int regular_file(const char *file, const char *msg);
+extern FILE *fopen_local(const char *file, const char *mode, const char *msg);
+extern void fclose_local(FILE *f, const char *msg);
+extern char *fgets_local(char **line, int *size, FILE *f, const char *msg);
+extern int fwrite_local(void const *ptr, size_t size, size_t nmemb,
+                       FILE *stream, const char *msg);
+extern FILE *popen_local(const char *cmd, const char *msg);
+extern void pclose_local(FILE *f, const char *msg);
+
+/* ksyms.c */
+extern void read_ksyms(const char *ksyms);
+extern void map_ksyms_to_modules(void);
+extern void read_lsmod(const char *lsmod);
+extern void compare_ksyms_lsmod(void);
+
+/* misc.c */
+extern void malloc_error(const char *msg);
+extern const char *format_address(elf_addr_t address);
+extern char *find_fullpath(const char *program);
+
+/* map.c */
+extern void read_system_map(const char *system_map);
+extern void merge_maps(const char *save_system_map);
+extern void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
+                        int precedence);
+
+
+/* object.c */
+extern SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss);
+extern void read_vmlinux(const char *vmlinux);
+extern void expand_objects(char * const *object, int objects);
+extern void read_object(const char *object, int i);
+
+/* oops.c */
+extern void Oops_read(int filecount, char * const *filename);
+
+/* re.c */
+extern void re_compile(regex_t *preg, const char *regex, int cflags,
+                      regmatch_t **pmatch);
+extern void re_compile_common(void);
+extern void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
+                      char ***string);
+extern void re_strings_free(const regex_t *preg, char ***string);
+extern void re_string_check(int need, int available, const char *msg);
+
+/* symbol.c */
+extern void ss_init(SYMBOL_SET *ss, const char *msg);
+extern void ss_free(SYMBOL_SET *ss);
+extern void ss_init_common(void);
+extern SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol,
+                               int *start);
+extern void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
+                        const char type, const char keep, const char *symbol);
+extern void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
+                      const char keep, const char *symbol);
+extern char *map_address(const SYMBOL_SET *ss, const elf_addr_t address);
+extern void ss_sort_atn(SYMBOL_SET *ss);
+extern void ss_sort_na(SYMBOL_SET *ss);
+extern SYMBOL_SET *ss_copy(const SYMBOL_SET *ss);
+extern void add_Version(const char *version, const char *source);
+extern void extract_Version(SYMBOL_SET *ss);
+extern void compare_Version(void);
diff --git a/scripts/ksymoops-0.6/ksyms.c b/scripts/ksymoops-0.6/ksyms.c
new file mode 100644 (file)
index 0000000..54b84b3
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+       ksyms.c.
+
+       Process ksyms for ksymoops.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Read lsmod (/proc/modules).
+       Move "Using_Version" copy to map.c.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <malloc.h>
+#include <string.h>
+
+/* Scan one line from ksyms.  Split lines into the base symbols and the module
+ * symbols.  Separate ss for base and each module.
+ */
+static void scan_ksyms_line(const char *line)
+{
+       int i;
+       char **string = NULL;
+       SYMBOL_SET *ssp;
+       static char *prev_module = NULL;
+       static regex_t     re_ksyms;
+       static regmatch_t *re_ksyms_pmatch;
+       static char const procname[] = "scan_ksyms_line";
+
+       /* ksyms: address, symbol, optional module */
+       re_compile(&re_ksyms,
+               "^([0-9a-fA-F]{4,}) +([^ \t]+)([ \t]+\\[([^ ]+)\\])?$",
+               REG_NEWLINE|REG_EXTENDED,
+               &re_ksyms_pmatch);
+
+       i = regexec(&re_ksyms, line,
+                   re_ksyms.re_nsub+1, re_ksyms_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i)
+               return;
+
+       /* string [1] - address, [2] - symbol, [3] - white space+module,
+        * [4] - module.
+        */
+       re_strings(&re_ksyms, line, re_ksyms_pmatch, &string);
+       if (string[4]) {
+               if (!prev_module || strcmp(prev_module, string[4])) {
+                       /* start of a new module in ksyms */
+                       ++ss_ksyms_modules;
+                       ss_ksyms_module = realloc(ss_ksyms_module,
+                               ss_ksyms_modules*sizeof(*ss_ksyms_module));
+                       if (!ss_ksyms_module)
+                               malloc_error("realloc ss_ksyms_module");
+                       ssp = ss_ksyms_module+ss_ksyms_modules-1;
+                       ss_init(ssp, string[4]);
+                       prev_module = strdup(string[4]);
+                       if (!prev_module)
+                               malloc_error("strdup prev_module");
+               }
+               ssp = ss_ksyms_module+ss_ksyms_modules-1;
+       }
+       else
+               ssp = &ss_ksyms_base;
+       add_symbol(ssp, string[1], ' ', 1, string[2]);
+       re_strings_free(&re_ksyms, &string);
+}
+
+/* Read the symbols from ksyms.  */
+void read_ksyms(const char *ksyms)
+{
+       FILE *f;
+       char *line = NULL;
+       int i, size;
+       static char const procname[] = "read_ksyms";
+
+       if (!ksyms)
+               return;
+       ss_init(&ss_ksyms_base, "ksyms_base");
+       if (debug)
+               fprintf(stderr, "DEBUG: %s %s\n", procname, ksyms);
+
+       if (!regular_file(ksyms, procname))
+               return;
+
+       if (!(f = fopen_local(ksyms, "r", procname)))
+               return;
+
+       while (fgets_local(&line, &size, f, procname))
+               scan_ksyms_line(line);
+
+       fclose_local(f, procname);
+       free(line);
+
+       for (i = 0; i < ss_ksyms_modules; ++i) {
+               ss_sort_na(ss_ksyms_module+i);
+               extract_Version(ss_ksyms_module+i);
+       }
+       if (ss_ksyms_base.used) {
+               ss_sort_na(&ss_ksyms_base);
+               extract_Version(&ss_ksyms_base);
+       }
+       else {
+               fprintf(stderr,
+                       "Warning, no kernel symbols in ksyms, is %s a valid "
+                       "ksyms file?\n",
+                       ksyms);
+               ++warnings;
+       }
+
+       if (debug > 1) {
+               for (i = 0; i < ss_ksyms_modules; ++i) {
+                       fprintf(stderr,
+                               "DEBUG: %s %s used %d out of %d entries\n",
+                               procname,
+                               ss_ksyms_module[i].source,
+                               ss_ksyms_module[i].used,
+                               ss_ksyms_module[i].alloc);
+               }
+               fprintf(stderr,
+                       "DEBUG: %s %s used %d out of %d entries\n",
+                       procname, ss_ksyms_base.source, ss_ksyms_base.used,
+                       ss_ksyms_base.alloc);
+       }
+}
+
+/* Map each ksyms module entry to the corresponding object entry.  Tricky,
+ * see the comments in the docs about needing a unique symbol in each
+ * module.
+ */
+static void map_ksym_to_module(SYMBOL_SET *ss)
+{
+       int i, j, matches;
+       char *name = NULL;
+
+       for (i = 0; i < ss->used; ++i) {
+               matches = 0;
+               for (j = 0; j < ss_objects; ++j) {
+                       name = (ss->symbol)[i].name;
+                       if (find_symbol_name(ss_object+j, name, NULL)) {
+                               ++matches;
+                               ss->related = ss_object+j;
+                       }
+               }
+               if (matches == 1)
+                       break;          /* unique symbol over all objects */
+               ss->related = NULL;     /* keep looking */
+       }
+       if (!(ss->related)) {
+               fprintf(stderr,
+                       "Warning: cannot match loaded module %s to any "
+                       "module object.  Trace may not be reliable.\n",
+                       ss->source);
+               ++warnings;
+       }
+       else if (debug)
+               fprintf(stderr,
+                       "DEBUG: ksyms %s matches to %s based on unique "
+                       "symbol %s\n",
+                       ss->source, ss->related->source, name);
+}
+
+/* Map all ksyms module entries to their corresponding objects */
+void map_ksyms_to_modules(void)
+{
+       int i;
+       SYMBOL_SET *ss, *ssc;
+
+       for (i = 0; i < ss_ksyms_modules; ++i) {
+               ss = ss_ksyms_module+i;
+               map_ksym_to_module(ss);
+               if (ss->related) {
+                       ssc = adjust_object_offsets(ss);
+                       compare_maps(ss, ssc, 1);
+               }
+       }
+}
+
+/* Read the modules from lsmod.  */
+void read_lsmod(const char *lsmod)
+{
+       FILE *f;
+       char *line = NULL;
+       int i, size;
+       char **string = NULL;
+       static regex_t     re_lsmod;
+       static regmatch_t *re_lsmod_pmatch;
+       static char const procname[] = "read_lsmod";
+
+       if (!lsmod)
+               return;
+       ss_init(&ss_lsmod, "lsmod");
+       if (debug)
+               fprintf(stderr, "DEBUG: %s %s\n", procname, lsmod);
+
+       if (!regular_file(lsmod, procname))
+               return;
+
+       if (!(f = fopen_local(lsmod, "r", procname)))
+               return;
+
+       /* lsmod: module, size, use count, optional used by */
+       re_compile(&re_lsmod,
+               "^"
+               "[ \t]*([^ \t]+)"                               /* 1 module */
+               "[ \t]*([^ \t]+)"                               /* 2 size */
+               "[ \t]*([^ \t]+)"                               /* 3 count */
+               "[ \t]*(.*)"                                    /* 4 used by */
+               "$",
+               REG_NEWLINE|REG_EXTENDED,
+               &re_lsmod_pmatch);
+
+       while (fgets_local(&line, &size, f, procname)) {
+               i = regexec(&re_lsmod, line,
+                           re_lsmod.re_nsub+1, re_lsmod_pmatch, 0);
+               if (debug > 3)
+                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+               if (i)
+                       continue;
+               re_strings(&re_lsmod, line, re_lsmod_pmatch, &string);
+               add_symbol(&ss_lsmod, string[2], ' ', 1, string[1]);
+       }
+
+       fclose_local(f, procname);
+       free(line);
+       re_strings_free(&re_lsmod, &string);
+       if (ss_lsmod.used)
+               ss_sort_na(&ss_lsmod);
+       else {
+               fprintf(stderr,
+                       "Warning, no symbols in lsmod, is %s a valid "
+                       "lsmod file?\n",
+                       lsmod);
+               ++warnings;
+       }
+
+       if (debug > 1)
+               fprintf(stderr,
+                       "DEBUG: %s %s used %d out of %d entries\n",
+                       procname, ss_lsmod.source, ss_lsmod.used,
+                       ss_lsmod.alloc);
+}
+
+/* Compare modules from ksyms against module list in lsmod and vice versa.
+ * There is one ss_ for each ksyms module and a single ss_lsmod to cross
+ * check.
+ */
+void compare_ksyms_lsmod(void)
+{
+       int i, j;
+       SYMBOL_SET *ss;
+       SYMBOL *s;
+       static char const procname[] = "compare_ksyms_lsmod";
+
+       s = ss_lsmod.symbol;
+       for (i = 0; i < ss_lsmod.used; ++i, ++s) {
+               for (j = 0; j < ss_ksyms_modules; ++j) {
+                       ss = ss_ksyms_module+j;
+                       if (strcmp(s->name, ss->source) == 0)
+                               break;
+               }
+               if (j >= ss_ksyms_modules) {
+                       fprintf(stderr,
+                               "Warning in %s, module %s is in lsmod but not "
+                               "in ksyms, probably no symbols exported\n",
+                               procname, s->name);
+                       ++warnings;
+               }
+       }
+
+       for (i = 0; i < ss_ksyms_modules; ++i) {
+               ss = ss_ksyms_module+i;
+               if (!find_symbol_name(&ss_lsmod, ss->source, NULL)) {
+                       fprintf(stderr,
+                               "Error in %s, module %s is in ksyms but not "
+                               "in lsmod\n",
+                               procname, ss->source);
+                       ++errors;
+               }
+       }
+}
diff --git a/scripts/ksymoops-0.6/map.c b/scripts/ksymoops-0.6/map.c
new file mode 100644 (file)
index 0000000..6f91e9d
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+       map.c.
+
+       Read System.map for ksymoops, create merged System.map.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Remove addresses 0-4095 from merged map after writing new map.
+       Move "Using_Version" copy to map.c.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <malloc.h>
+
+/* Read the symbols from System.map */
+void read_system_map(const char *system_map)
+{
+       FILE *f;
+       char *line = NULL, **string = NULL;
+       int i, size = 0;
+       static char const procname[] = "read_system_map";
+
+       if (!system_map)
+               return;
+       ss_init(&ss_system_map, "System.map");
+       if (debug)
+               fprintf(stderr, "DEBUG: %s %s\n", procname, system_map);
+
+       if (!regular_file(system_map, procname))
+               return;
+
+       if (!(f = fopen_local(system_map, "r", procname)))
+               return;
+
+       while (fgets_local(&line, &size, f, procname)) {
+               i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
+               if (debug > 3)
+                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+               if (i == 0) {
+                       re_strings(&re_nm, line, re_nm_pmatch, &string);
+                       add_symbol(&ss_system_map, string[1], *string[2],
+                                  1, string[3]);
+               }
+       }
+
+       fclose_local(f, procname);
+       re_strings_free(&re_nm, &string);
+       free(line);
+       if (ss_system_map.used) {
+               ss_sort_na(&ss_system_map);
+               extract_Version(&ss_system_map);
+       }
+       else {
+               fprintf(stderr,
+                       "Warning, no kernel symbols in System.map, is %s a "
+                       "valid System.map file?\n",
+                       system_map);
+               ++warnings;
+       }
+
+       if (debug > 1)
+               fprintf(stderr,
+                       "DEBUG: %s %s used %d out of %d entries\n",
+                       procname,
+                       ss_system_map.source,
+                       ss_system_map.used,
+                       ss_system_map.alloc);
+}
+
+/* Compare two maps, all symbols in the first should appear in the second. */
+void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
+                        int precedence)
+{
+       int i, start = 0;
+       SYMBOL *s1, *s2, **sdrop = precedence == 1 ? &s2 : &s1;
+       const SYMBOL_SET **ssdrop = precedence == 1 ? &ss2 : &ss1;
+
+       if (!(ss1->used && ss2->used))
+               return;
+
+       if (debug > 1)
+               fprintf(stderr,
+                       "DEBUG: compare_maps %s vs %s, %s takes precedence\n",
+                       ss1->source, ss2->source,
+                       precedence == 1 ? ss1->source : ss2->source);
+
+       for (i = 0; i < ss1->used; ++i) {
+               s1 = ss1->symbol+i;
+               if (!(s1->keep))
+                       continue;
+               s2 = find_symbol_name(ss2, s1->name, &start);
+               if (!s2) {
+                       /* Some types only appear in nm output, not in things
+                        * like System.map.  Silently ignore them.
+                        */
+                       if (s1->type == 'a' || s1->type == 't')
+                               continue;
+                       fprintf(stderr,
+                               "Warning: %s symbol %s not found in %s.  "
+                               "Ignoring %s entry\n",
+                               ss1->source, s1->name,
+                               ss2->source, (*ssdrop)->source);
+                       ++warnings;
+                       if (*sdrop)
+                               (*sdrop)->keep = 0;
+               }
+               else if (s1->address != s2->address) {
+                       /* Type C symbols cannot be resolved from nm to ksyms,
+                        * silently ignore them.
+                        */
+                       if (s1->type == 'C' || s2->type == 'C')
+                               continue;
+                       fprintf(stderr,
+                               "Warning: mismatch on symbol %s %c, "
+                               "%s says %lx, %s says %lx.  "
+                               "Ignoring %s entry\n",
+                               s1->name, s1->type, ss1->source, s1->address,
+                               ss2->source, s2->address, (*ssdrop)->source);
+                       ++warnings;
+                       if (*sdrop)
+                               (*sdrop)->keep = 0;
+               }
+               else
+                       ++start;        /* step to next entry in ss2 */
+       }
+}
+
+/* Append the second symbol set onto the first */
+static void append_map(SYMBOL_SET *ss1, const SYMBOL_SET *ss2)
+{
+       int i;
+       SYMBOL *s;
+
+       if (!ss2 || !ss2->used)
+               return;
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: append_map %s to %s\n",
+                       ss2->source, ss1->source);
+
+       for (i = 0; i < ss2->used; ++i) {
+               s = ss2->symbol+i;
+               if (s->keep)
+                       add_symbol_n(ss1, s->address, s->type, 1,
+                               s->name);
+       }
+}
+
+/* Compare the various sources and build a merged system map */
+void merge_maps(const char *save_system_map)
+{
+       int i;
+       SYMBOL *s;
+       FILE *f;
+       static char const procname[] = "merge_maps";
+
+       if (debug)
+               fprintf(stderr, "DEBUG: %s\n", procname);
+
+       /* Using_Versions only appears in ksyms, copy to other tables */
+       if ((s = find_symbol_name(&ss_ksyms_base,
+                       "Using_Versions", 0))) {
+               if (ss_system_map.used) {
+                       add_symbol_n(&ss_system_map, s->address,
+                               s->type, s->keep, s->name);
+                       ss_sort_na(&ss_system_map);
+               }
+               if (ss_vmlinux.used) {
+                       add_symbol_n(&ss_vmlinux, s->address, s->type,
+                               s->keep, s->name);
+                       ss_sort_na(&ss_vmlinux);
+               }
+       }
+
+       compare_Version();      /* highlight any version problems first */
+       compare_ksyms_lsmod();  /* highlight any missing modules next */
+       compare_maps(&ss_ksyms_base, &ss_vmlinux, 2);
+       compare_maps(&ss_system_map, &ss_vmlinux, 2);
+       compare_maps(&ss_vmlinux, &ss_system_map, 1);
+       compare_maps(&ss_ksyms_base, &ss_system_map, 2);
+
+       if (ss_objects) {
+               map_ksyms_to_modules();
+       }
+
+       ss_init(&ss_merged, "merged");
+       append_map(&ss_merged, &ss_vmlinux);
+       append_map(&ss_merged, &ss_ksyms_base);
+       append_map(&ss_merged, &ss_system_map);
+       for (i = 0; i < ss_ksyms_modules; ++i)
+               append_map(&ss_merged, (ss_ksyms_module+i)->related);
+       if (!ss_merged.used) {
+               fprintf(stderr, "Warning, no symbols in merged map\n");
+               ++warnings;
+       }
+
+       /* drop duplicates, type a (registers) and gcc2_compiled. */
+       ss_sort_atn(&ss_merged);
+       s = ss_merged.symbol;
+       for (i = 0; i < ss_merged.used-1; ++i) {
+               if (s->type == 'a' ||
+                   (s->type == 't' && !strcmp(s->name, "gcc2_compiled.")))
+                       s->keep = 0;
+               else if (strcmp(s->name, (s+1)->name) == 0 &&
+                   s->address == (s+1)->address) {
+                       if (s->type != ' ')
+                               (s+1)->keep = 0;
+                       else
+                               s->keep = 0;
+               }
+               ++s;
+       }
+       ss_sort_atn(&ss_merged);        /* will remove dropped variables */
+
+       if (save_system_map) {
+               if (debug)
+                       fprintf(stderr, "DEBUG: writing merged map to %s\n",
+                               save_system_map);
+               if (!(f = fopen_local(save_system_map, "w", procname)))
+                       return;
+               s = ss_merged.symbol;
+               for (i = 0; i < ss_merged.used; ++i) {
+                       if (s->keep)
+                               fprintf(f, "%s %c %s\n",
+                                       format_address(s->address),
+                                       s->type, s->name);
+                       ++s;
+               }
+       }
+
+       /* The merged map may contain symbols with an address of 0, e.g.
+        * Using_Versions.  These give incorrect results for low addresses in
+        * map_address, such addresses map to "Using_Versions+xxx".  Remove
+        * any addresses below (arbitrary) 4096 from the merged map.  AFAIK,
+        * Linux does not use the first page on any arch.
+        */
+       for (i = 0; i < ss_merged.used; ++i) {
+               if ((ss_merged.symbol+i)->address < 4096)
+                       (ss_merged.symbol+i)->keep = 0;
+               else
+                       break;
+       }
+       if (i)
+               ss_sort_atn(&ss_merged);        /* remove dropped variables */
+}
diff --git a/scripts/ksymoops-0.6/misc.c b/scripts/ksymoops-0.6/misc.c
new file mode 100644 (file)
index 0000000..7876f7e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+       misc.c.
+
+       Miscellaneous routines for ksymoops.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Convert from a.out to bfd, using same format as ksymoops.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void malloc_error(const char *msg)
+{
+       fprintf(stderr, "%s: fatal malloc error for %s\n", prefix, msg);
+       exit(2);
+}
+
+/* Format an address with the correct number of leading zeroes */
+const char *format_address(elf_addr_t address)
+{
+       /* Well oversized */
+       static char format[10], text[200];
+       if (!*format)
+               snprintf(format, sizeof(format), "%%0%dlx",
+                       2*sizeof(address));
+       snprintf(text, sizeof(text), format, address);
+       return(text);
+}
+
+/* Find the full pathname of a program.  Code heavily based on
+ * glibc-2.0.5/posix/execvp.c.
+ */
+char *find_fullpath(const char *program)
+{
+       char *fullpath = NULL;
+       char *path, *p;
+       size_t len;
+       static const char procname[] = "find_fullpath";
+
+       /* Don't search when it contains a slash.  */
+       if (strchr(program, '/')) {
+               if (!(fullpath = strdup(program)))
+                       malloc_error(procname);
+               if (debug > 1)
+                       fprintf(stderr, "DEBUG: %s %s\n", procname, fullpath);
+               return(fullpath);
+       }
+
+       path = getenv ("PATH");
+       if (!path) {
+               /* There is no `PATH' in the environment.  The default search
+                  path is the current directory followed by the path `confstr'
+                  returns for `_CS_PATH'.
+                */
+               len = confstr(_CS_PATH, (char *) NULL, 0);
+               if (!(path = malloc(1 + len)))
+                       malloc_error(procname);
+               path[0] = ':';
+               confstr(_CS_PATH, path+1, len);
+       }
+
+       len = strlen(program) + 1;
+       if (!(fullpath = malloc(strlen(path) + len)))
+               malloc_error(procname);
+       p = path;
+       do {
+               path = p;
+               p = strchr(path, ':');
+               if (p == NULL)
+                       p = strchr(path, '\0');
+
+               /* Two adjacent colons, or a colon at the beginning or the end
+                * of `PATH' means to search the current directory.
+                */
+               if (p == path)
+                       memcpy(fullpath, program, len);
+               else {
+                       /* Construct the pathname to try.  */
+                       memcpy(fullpath, path, p - path);
+                       fullpath[p - path] = '/';
+                       memcpy(&fullpath[(p - path) + 1], program, len);
+               }
+
+               /* If we have execute access, assume this is the program. */
+               if (access(fullpath, X_OK) == 0) {
+                       if (debug > 1)
+                               fprintf(stderr, "DEBUG: %s %s\n",
+                                       procname, fullpath);
+                       return(fullpath);
+               }
+       } while (*p++ != '\0');
+
+       fprintf(stderr, "Error: %s %s could not find executable %s\n",
+               prefix, procname, program);
+       ++errors;
+       return(NULL);
+}
diff --git a/scripts/ksymoops-0.6/object.c b/scripts/ksymoops-0.6/object.c
new file mode 100644 (file)
index 0000000..7a44e4c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+       object.c.
+
+       object handling routines for ksymoops.  Read modules, vmlinux, etc. 
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <malloc.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* Extract all symbols definitions from an object using nm */
+static void read_nm_symbols(SYMBOL_SET *ss, const char *file)
+{
+       FILE *f;
+       char *cmd, *line = NULL, **string = NULL;
+       int i, size = 0;
+       static char const procname[] = "read_nm_symbols";
+
+       if (!regular_file(file, procname))
+               return;
+
+       cmd = malloc(strlen(path_nm)+strlen(file)+2);
+       if (!cmd)
+               malloc_error("nm command");
+       strcpy(cmd, path_nm);
+       strcat(cmd, " ");
+       strcat(cmd, file);
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
+       if (!(f = popen_local(cmd, procname)))
+               return;
+       free(cmd);
+
+       while (fgets_local(&line, &size, f, procname)) {
+               i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
+               if (debug > 3)
+                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+               if (i == 0) {
+                       re_strings(&re_nm, line, re_nm_pmatch, &string);
+                       add_symbol(ss, string[1], *string[2], 1, string[3]);
+               }
+       }
+
+       pclose_local(f, procname);
+       re_strings_free(&re_nm, &string);
+       free(line);
+       if (debug > 1)
+               fprintf(stderr,
+                       "DEBUG: %s %s used %d out of %d entries\n",
+                       procname, ss->source, ss->used, ss->alloc);
+}
+
+/* Read the symbols from vmlinux */
+void read_vmlinux(const char *vmlinux)
+{
+       if (!vmlinux)
+               return;
+       ss_init(&ss_vmlinux, "vmlinux");
+       read_nm_symbols(&ss_vmlinux, vmlinux);
+       if (ss_vmlinux.used) {
+               ss_sort_na(&ss_vmlinux);
+               extract_Version(&ss_vmlinux);
+       }
+       else {
+               fprintf(stderr,
+                       "Warning, no kernel symbols in vmlinux, is %s a valid "
+                       "vmlinux file?\n",
+                       vmlinux);
+               ++warnings;
+       }
+}
+
+
+/* Read the symbols from one object (module) */
+void read_object(const char *object, int i)
+{
+       ss_init(ss_object+i, object);
+       read_nm_symbols(ss_object+i, object);
+       if ((ss_object+i)->used) {
+               ss_sort_na(ss_object+i);
+               extract_Version(ss_object+i);
+       }
+       else {
+               fprintf(stderr, "Warning, no symbols in %s\n", object);
+               ++warnings;
+       }
+}
+
+/* Add a new entry to the list of objects */
+static void add_ss_object(const char *file)
+{
+       ++ss_objects;
+       ss_object = realloc(ss_object, ss_objects*sizeof(*ss_object));
+       if (!ss_object)
+               malloc_error("realloc ss_object");
+       ss_init(ss_object+ss_objects-1, file);
+}
+
+/* Run a directory and its subdirectories, looking for *.o files */
+static void find_objects(const char *dir)
+{
+       FILE *f;
+       char *cmd, *line = NULL;
+       int size = 0, files = 0;
+       static char const procname[] = "find_objects";
+       static char const options[] = " -follow -name '*.o' -print";
+
+       cmd = malloc(strlen(path_find)+1+strlen(dir)+strlen(options)+1);
+       if (!cmd)
+               malloc_error("find command");
+       strcpy(cmd, path_find);
+       strcat(cmd, " ");
+       strcat(cmd, dir);
+       strcat(cmd, options);
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
+       if (!(f = popen_local(cmd, procname)))
+               return;
+       free(cmd);
+
+       while (fgets_local(&line, &size, f, procname)) {
+               if (debug > 1)
+                       fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
+               add_ss_object(line);
+               ++files;
+       }
+
+       pclose_local(f, procname);
+       if (!files) {
+               fprintf(stderr,
+                       "Warning: no *.o files in %s.  "
+                       "Is %s a valid module directory?\n",
+                       dir, dir);
+               ++warnings;
+       }
+}
+
+/* Take the user supplied list of objects which can include directories.
+ * Expand directories into any *.o files.  The results are stored in
+ * ss_object, leaving the user supplied options untouched.
+ */
+void expand_objects(char * const *object, int objects)
+{
+       struct stat statbuf;
+       int i;
+       const char *file;
+       static char const procname[] = "expand_objects";
+
+       for (i = 0; i < objects; ++i) {
+               file = object[i];
+               if (debug > 1)
+                       fprintf(stderr, "DEBUG: %s checking '%s' - ",
+                               procname, file);
+               if (!stat(file, &statbuf) && S_ISDIR(statbuf.st_mode)) {
+                       if (debug > 1)
+                               fprintf(stderr, "directory, expanding\n");
+                       find_objects(file);
+               }
+               else {
+                       if (debug > 1)
+                               fprintf(stderr, "not directory\n");
+                       add_ss_object(file);
+               }
+       }
+}
+
+/* Map a symbol type to a section code. 0 - text, 1 - data, 2 - read only data,
+ * 3 - C (cannot relocate), 4 - the rest.
+ */
+static int section(char type)
+{
+       switch (type) {
+       case 'T':
+       case 't':
+               return 0;
+       case 'D':
+       case 'd':
+               return 1;
+       case 'R':
+       case 'r':
+               return 2;
+       case 'C':
+               return 3;
+       default:
+               return 4;
+       }
+}
+
+/* Given ksyms module data which has a related object, create a copy of the
+ * object data, adjusting the offsets to match where the module was loaded.
+ */
+SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss)
+{
+       int i;
+       elf_addr_t adjust[] = {0, 0, 0, 0, 0};
+       SYMBOL *sk, *so;
+       SYMBOL_SET *ssc;
+
+       if (debug > 1)
+               fprintf(stderr,
+                       "DEBUG: adjust_object_offsets %s\n", ss->source);
+
+       ssc = ss_copy(ss->related);
+
+       /* For common symbols, calculate the adjustment */
+       for (i = 0; i < ss->used; ++i) {
+               sk = ss->symbol+i;
+               if ((so = find_symbol_name(ssc, sk->name, NULL)))
+                       adjust[section(so->type)] = sk->address - so->address;
+       }
+       for (i = 0; i < ssc->used; ++i) {
+               so = ssc->symbol+i;
+               /* Type C does not relocate well, silently ignore */
+               if (so->type != 'C' && adjust[section(so->type)])
+                       so->address += adjust[section(so->type)];
+               else
+                       so->keep = 0;  /* do not merge into final map */
+       }
+
+       ss->related = ssc;      /* map using adjusted copy */
+       return(ssc);
+}
diff --git a/scripts/ksymoops-0.6/oops.c b/scripts/ksymoops-0.6/oops.c
new file mode 100644 (file)
index 0000000..e0f05fd
--- /dev/null
@@ -0,0 +1,1061 @@
+/*
+       oops.c.
+
+       Oops processing for ksymoop.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Oops file must be regular.
+       Add "invalid operand" to Oops_print.
+       Minor adjustment to re for ppc.
+       Minor adjustment to re for objdump lines with <_EIP+xxx>.
+       Convert from a.out to bfd, using same format as ksymoops.
+       Added MIPS.
+       PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into seperate sources.
+ */
+
+#include "ksymoops.h"
+#include <bfd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <malloc.h>
+#include <memory.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Error detected by bfd */
+static void Oops_bfd_perror(const char *msg)
+{
+       fprintf(stderr, "Error ");
+       bfd_perror(msg);
+       ++errors;
+}
+
+/* Safest way to get correct output bfd format is to copy ksymoops' format. */
+static int Oops_copy_bfd_format(bfd **ibfd, bfd **obfd, asection **isec,
+                               const char *file)
+{
+       char *me, **matches, **match;
+
+       if (!(*obfd = bfd_openw(file, NULL))) {
+               Oops_bfd_perror(file);
+               return(0);
+       }
+
+       me = find_fullpath(prefix);
+       if (!me)
+               return(0);
+
+       if (!(*ibfd = bfd_openr(me, NULL))) {
+               Oops_bfd_perror(me);
+               return(0);
+       }
+       free(me);       /* Who is Tommy? */
+
+       if (!bfd_check_format_matches(*ibfd, bfd_object, &matches)) {
+               Oops_bfd_perror(me);
+               if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
+                       fprintf(stderr, "Matching formats:");
+                       match = matches;
+                       while (*match)
+                               fprintf(stderr, " %s", *match++);
+                       fprintf(stderr, "\n");
+                       free(matches);
+               }
+               return(0);
+       }
+
+       if (!(*isec = bfd_get_section_by_name(*ibfd, ".text"))) {
+               Oops_bfd_perror("get_section");
+               return(0);
+       }
+
+       bfd_set_format(*obfd, bfd_object);
+       bfd_set_arch_mach(*obfd, bfd_get_arch(*ibfd), bfd_get_mach(*ibfd));
+
+       if (!bfd_set_file_flags(*obfd, bfd_get_file_flags(*ibfd))) {
+               Oops_bfd_perror("set_file_flags");
+               return(0);
+       }
+
+       return(1);
+}
+
+/* Write the code values to a file using bfd. */
+static int Oops_write_bfd_data(bfd *ibfd, bfd *obfd, asection *isec,
+                              const char *code, int size)
+{
+       asection *osec;
+       asymbol *osym;
+
+       if (!bfd_set_start_address(obfd, 0)) {
+               Oops_bfd_perror("set_start_address");
+               return(0);
+       }
+       if (!(osec = bfd_make_section(obfd, ".text"))) {
+               Oops_bfd_perror("make_section");
+               return(0);
+       }
+       if (!bfd_set_section_flags(obfd, osec, 
+               bfd_get_section_flags(ibfd, isec))) {
+               Oops_bfd_perror("set_section_flags");
+               return(0);
+       }
+       if (!bfd_set_section_alignment(obfd, osec, 
+               bfd_get_section_alignment(ibfd, isec))) {
+               Oops_bfd_perror("set_section_alignment");
+               return(0);
+       }
+       osec->output_section = osec;
+       if (!(osym = bfd_make_empty_symbol(obfd))) {
+               Oops_bfd_perror("make_empty_symbol");
+               return(0);
+       }
+       osym->name = "_EIP";
+       osym->section = osec;
+       osym->flags = BSF_GLOBAL;
+       osym->value = 0;
+       if (!bfd_set_symtab(obfd, &osym, 1)) {
+               Oops_bfd_perror("set_symtab");
+               return(0);
+       }
+       if (!bfd_set_section_size(obfd, osec, size)) {
+               Oops_bfd_perror("set_section_size");
+               return(0);
+       }
+       if (!bfd_set_section_vma(obfd, osec, 0)) {
+               Oops_bfd_perror("set_section_vma");
+               return(0);
+       }
+       if (!bfd_set_section_contents(obfd, osec, (PTR) code, 0, size)) {
+               Oops_bfd_perror("set_section_contents");
+               return(0);
+       }
+       if (!bfd_close(obfd)) {
+               Oops_bfd_perror("close(obfd)");
+               return(0);
+       }
+       if (!bfd_close(ibfd)) {
+               Oops_bfd_perror("close(ibfd)");
+               return(0);
+       }
+       return 1;
+}
+
+/* Write the Oops code to a temporary file with suitable header and trailer. */
+static char *Oops_code_to_file(const char *code, int size)
+{
+       char *file;
+       bfd *ibfd, *obfd;
+       asection *isec;
+
+       bfd_init();
+       file = tmpnam(NULL);
+       if (!Oops_copy_bfd_format(&ibfd, &obfd, &isec, file))
+               return(NULL);
+       if (!Oops_write_bfd_data(ibfd, obfd, isec, code, size))
+               return(NULL);
+       return(file);
+}
+
+/* Run objdump against the binary Oops code */
+static FILE *Oops_objdump(const char *file)
+{
+       char *cmd;
+       FILE *f;
+       static char const options[] = "-dhf ";
+       static char const procname[] = "Oops_objdump";
+
+       cmd = malloc(strlen(path_objdump)+1+strlen(options)+strlen(file)+1);
+       if (!cmd)
+               malloc_error(procname);
+       strcpy(cmd, path_objdump);
+       strcat(cmd, " ");
+       strcat(cmd, options);
+       strcat(cmd, file);
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
+       f = popen_local(cmd, procname);
+       free(cmd);
+       return(f);
+}
+
+/* Process one code line from objdump, ignore everything else */
+static void Oops_decode_one(SYMBOL_SET *ss, const char *line, elf_addr_t eip,
+                           int adjust)
+{
+       int i;
+       elf_addr_t address, eip_relative;
+       char *line2, *map, **string = NULL;
+       static regex_t     re_Oops_objdump;
+       static regmatch_t *re_Oops_objdump_pmatch;
+       static char const procname[] = "Oops_decode_one";
+
+       /* objdump output.  Optional whitespace, hex digits, optional
+        * ' <_EIP+offset>', ':'.  The '+offset' after _EIP is also optional.
+        * Older binutils output 'xxxxxxxx <_EIP+offset>:', newer versions do
+        * '00000000 <_EIP>:' first followed by '      xx:' lines.
+        *
+        * Just to complicate things even more, objdump recognises jmp, call,
+        * etc., converts the code to something like this :-
+        * "   f: e8 32 34 00 00  call   3446 <_EIP+0x3446>"
+        * Recognise this and append the eip adjusted address, followed by the
+        * map_address text for that address.
+        *
+        * With any luck, objdump will take care of all such references which
+        * makes this routine architecture insensitive.  No need to test for
+        * i386 jmp, call or m68k swl etc.
+        */
+       re_compile(&re_Oops_objdump,
+                       "^[ \t]*"
+                       "([0-9a-fA-F]+)"                                /* 1 */
+                       "( <_EIP[^>]*>)?"                               /* 2 */
+                       ":"
+                       "("                                             /* 3 */
+                       ".* +<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$"        /* 4 */
+                       ")?"
+                       ".*"
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_objdump_pmatch);
+
+       i = regexec(&re_Oops_objdump, line, re_Oops_objdump.re_nsub+1,
+               re_Oops_objdump_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i != 0)
+               return;
+
+       re_strings(&re_Oops_objdump, line, re_Oops_objdump_pmatch, &string);
+       errno = 0;
+       address = strtoul(string[1], NULL, 16);
+       if (errno) {
+               fprintf(stderr,
+                       "%s Invalid hex value in objdump line, "
+                       "treated as zero - '%s'\n"
+                       "  objdump line '%s'\n",
+                       procname, string[1], line);
+               perror(" ");
+               ++errors;
+               address = 0;
+       }
+       address += eip + adjust;
+       if (string[4]) {
+               /* EIP relative data to be adjusted */
+               errno = 0;
+               eip_relative = strtoul(string[4], NULL, 16);
+               if (errno) {
+                       fprintf(stderr,
+                               "%s Invalid hex value in objdump line, "
+                               "treated as zero - '%s'\n"
+                               "  objdump line '%s'\n",
+                               procname, string[4], line);
+                       perror(" ");
+                       ++errors;
+                       eip_relative = 0;
+               }
+               eip_relative += eip + adjust;
+               map = map_address(&ss_merged, eip_relative);
+               /* new text is original line, eip_relative in hex, map text */
+               i = strlen(line)+1+2*sizeof(eip_relative)+1+strlen(map)+1;
+               line2 = malloc(i);
+               if (!line2)
+                       malloc_error(procname);
+               snprintf(line2, i, "%s %s %s",
+                       line, format_address(eip_relative), map);
+               add_symbol_n(ss, address, 'C', 1, line2);
+               free(line2);
+       }
+       else
+               add_symbol_n(ss, address, 'C', 1, line);        /* as is */
+       re_strings_free(&re_Oops_objdump, &string);
+}
+
+/* Maximum number of code bytes to process */
+#define CODE_SIZE 36   /* sparc and alpha dump 36 bytes */
+
+/******************************************************************************/
+/*                     Start architecture sensitive code                      */
+/******************************************************************************/
+
+/* Extract the hex values from the Code: line and convert to binary */
+static int Oops_code_values(const unsigned char* code_text, char *code,
+                           int *adjust, char ***string, int string_max)
+{
+       int byte = 0, l;
+       unsigned long c;
+       char *value;
+       const char *p;
+       static regex_t     re_Oops_code_value;
+       static regmatch_t *re_Oops_code_value_pmatch;
+       static const char procname[] = "Oops_code_values";
+
+       /* Given by re_Oops_code: code_text is a message (e.g. "general
+        * protection") or one or more hex fields separated by space or tab.
+        * Some architectures bracket the current instruction with '<' and '>'.
+        * The first character is nonblank.
+        */
+       if (!isxdigit(*code_text)) {
+               fprintf(stderr,
+                       "Warning, Code looks like message, not hex digits.  "
+                       "No disassembly attempted.\n");
+               ++warnings;
+               return(0);
+       }
+       memset(code, '\0', CODE_SIZE);
+       p = code_text;
+       *adjust = 0;    /* EIP points to code byte 0 */
+
+       /* Code values.  Hex values separated by white space.  On sparc, the
+        * current instruction is bracketed in '<' and '>'.
+        */
+       re_compile(&re_Oops_code_value,
+                       "^"
+                       "(<?)"                                          /* 1 */
+                       "([0-9a-fA-F]+)"                                /* 2 */
+                       ">?"
+                       "[ \t]*"
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_code_value_pmatch);
+
+       re_string_check(re_Oops_code_value.re_nsub+1, string_max, procname);
+       while (regexec(&re_Oops_code_value, p, re_Oops_code_value.re_nsub+1,
+                       re_Oops_code_value_pmatch, 0) == 0) {
+               re_strings(&re_Oops_code_value, p,
+                       re_Oops_code_value_pmatch, string);
+               if (byte >= CODE_SIZE)
+                       break;
+               errno = 0;
+               value = (*string)[2];
+               c = strtoul(value, NULL, 16);
+               if (errno) {
+                       fprintf(stderr,
+                               "%s Invalid hex value in code_value line, "
+                               "treated as zero - '%s'\n"
+                               "  code_value line '%s'\n",
+                               procname, value, code_text);
+                       perror(" ");
+                       ++errors;
+                       c = 0;
+               }
+               if ((*string[1]) && *((*string)[1]))
+                       *adjust = -byte;        /* this byte is EIP */
+               /* i386 - 2 byte code, m68k - 4 byte, sparc - 8 byte.
+                * Consistent we're not!
+                */
+               l = strlen(value);
+               if (l%2) {
+                       fprintf(stderr,
+                               "%s invalid value 0x%s in Code line, not a "
+                               "multiple of 2 digits, value ignored\n",
+                               procname, value);
+                       ++errors;
+               }
+               else while (l) {
+                       if (byte >= CODE_SIZE) {
+                               fprintf(stderr,
+                                       "%s Warning: extra values in Code "
+                                       "line, ignored - '%s'\n",
+                                       procname, value);
+                               ++warnings;
+                               break;
+                       }
+                       l -= 2;
+                       code[byte++] = (c >> l*4) & 0xff;
+                       value += 2;
+               }
+               p += re_Oops_code_value_pmatch[0].rm_eo;
+       }
+
+       if (*p) {
+               fprintf(stderr,
+                       "Warning garbage '%s' at end of code line ignored "
+                       "by %s\n",
+                       p, procname);
+               ++warnings;
+       }
+       return(1);
+}
+
+/* Look for the EIP: line, returns start of the relevant hex value */
+static char *Oops_eip(const char *line, char ***string, int string_max)
+{
+       int i;
+       static regex_t     re_Oops_eip_sparc;
+       static regmatch_t *re_Oops_eip_sparc_pmatch;
+       static regex_t     re_Oops_eip_ppc;
+       static regmatch_t *re_Oops_eip_ppc_pmatch;
+       static regex_t     re_Oops_eip_mips;
+       static regmatch_t *re_Oops_eip_mips_pmatch;
+       static regex_t     re_Oops_eip_other;
+       static regmatch_t *re_Oops_eip_other_pmatch;
+       static const char procname[] = "Oops_eip";
+
+       /* Oops 'EIP:' line for sparc, actually PSR followed by PC */
+       re_compile(&re_Oops_eip_sparc,
+                       "^PSR: [0-9a-fA-F]+ PC: " UNBRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_eip_sparc_pmatch);
+
+       re_string_check(re_Oops_eip_sparc.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_eip_sparc, line, re_Oops_eip_sparc.re_nsub+1,
+               re_Oops_eip_sparc_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec sparc %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_eip_sparc, line, re_Oops_eip_sparc_pmatch,
+                       string);
+               return((*string)[re_Oops_eip_sparc.re_nsub]);
+       }
+
+       /* Oops 'EIP:' line for PPC, all over the place */
+       re_compile(&re_Oops_eip_ppc,
+                       "("
+                         "(kernel pc )"
+                         "|(trap at PC: )"
+                         "|(bad area pc )"
+                         "|(NIP: )"
+                       ")"
+                       UNBRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_eip_ppc_pmatch);
+
+       re_string_check(re_Oops_eip_ppc.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_eip_ppc, line, re_Oops_eip_ppc.re_nsub+1,
+               re_Oops_eip_ppc_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec ppc %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_eip_ppc, line, re_Oops_eip_ppc_pmatch,
+                       string);
+               return((*string)[re_Oops_eip_ppc.re_nsub]);
+       }
+
+       /* Oops 'EIP:' line for MIPS, epc, optional white space, ':',
+        * optional white space, unbracketed address.
+        */
+       re_compile(&re_Oops_eip_mips,
+                       "^(epc[ \t]*:+[ \t]*)"
+                       UNBRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_eip_mips_pmatch);
+
+       re_string_check(re_Oops_eip_mips.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_eip_mips, line, re_Oops_eip_mips.re_nsub+1,
+               re_Oops_eip_mips_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec mips %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_eip_mips, line, re_Oops_eip_mips_pmatch,
+                       string);
+               return((*string)[re_Oops_eip_mips.re_nsub]);
+       }
+
+       /* Oops 'EIP:' line for other architectures */
+       re_compile(&re_Oops_eip_other,
+                       "^("
+       /* i386 */      "(EIP:[ \t]+.*)"
+       /* m68k */      "|(PC[ \t]*=[ \t]*)"
+                       ")"
+                       BRACKETED_ADDRESS
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_eip_other_pmatch);
+
+       re_string_check(re_Oops_eip_other.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_eip_other, line, re_Oops_eip_other.re_nsub+1,
+               re_Oops_eip_other_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec other %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_eip_other, line, re_Oops_eip_other_pmatch,
+                       string);
+               return((*string)[re_Oops_eip_other.re_nsub]);
+       }
+       return(NULL);
+}
+
+/* Set the eip from the EIP line */
+static void Oops_set_eip(const char *value, elf_addr_t *eip, SYMBOL_SET *ss)
+{
+       static const char procname[] = "Oops_set_eip";
+       errno = 0;
+       *eip = strtoul(value, NULL, 16);
+       if (errno) {
+               fprintf(stderr,
+                       "%s Invalid hex value in EIP line, ignored - '%s'\n",
+                       procname, value);
+               perror(" ");
+               ++errors;
+               *eip = 0;
+       }
+       add_symbol_n(ss, *eip, 'E', 1, ">>EIP:");
+}
+
+/* Look for the MIPS ra line, returns start of the relevant hex value */
+static char *Oops_ra(const char *line, char ***string, int string_max)
+{
+       int i;
+       static regex_t     re_Oops_ra;
+       static regmatch_t *re_Oops_ra_pmatch;
+       static const char procname[] = "Oops_ra";
+
+       /* Oops 'ra:' line for MIPS, ra, optional white space, one or
+        * more '=', optional white space, unbracketed address.
+        */
+       re_compile(&re_Oops_ra,
+                       "(ra[ \t]*=+[ \t]*)"
+                       UNBRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_ra_pmatch);
+
+       re_string_check(re_Oops_ra.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_ra, line, re_Oops_ra.re_nsub+1,
+               re_Oops_ra_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_ra, line, re_Oops_ra_pmatch,
+                       string);
+               return((*string)[re_Oops_ra.re_nsub]);
+       }
+       return(NULL);
+}
+
+/* Set the MIPS ra from the ra line */
+static void Oops_set_ra(const char *value, SYMBOL_SET *ss)
+{
+       static const char procname[] = "Oops_set_ra";
+       elf_addr_t ra;
+       errno = 0;
+       ra = strtoul(value, NULL, 16);
+       if (errno) {
+               fprintf(stderr,
+                       "%s Invalid hex value in ra line, ignored - '%s'\n",
+                       procname, value);
+               perror(" ");
+               ++errors;
+               ra = 0;
+       }
+       add_symbol_n(ss, ra, 'R', 1, ">>RA :");
+}
+
+/* Look for the Trace multilines :(.  Returns start of addresses. */
+static const char *Oops_trace(const char *line, char ***string, int string_max)
+{
+       int i;
+       const char *start = NULL;
+       static int trace_line = 0;
+       static regex_t     re_Oops_trace;
+       static regmatch_t *re_Oops_trace_pmatch;
+       static const char procname[] = "Oops_trace";
+
+       /* ppc is different, not a bracketed address, just an address */
+
+       /* Oops 'Trace' lines */
+       re_compile(&re_Oops_trace,
+                       "^(Call Trace: )"                       /*  1 */
+       /* alpha */     "|^(Trace: )"                           /*  2 */
+       /* various */   "|(" BRACKETED_ADDRESS ")"              /* 3,4*/
+       /* ppc */       "|^(Call backtrace:)"                   /*  5 */
+       /* ppc */       "|^(" UNBRACKETED_ADDRESS ")"           /* 6,7*/
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_trace_pmatch);
+
+       re_string_check(re_Oops_trace.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_trace, line, re_Oops_trace.re_nsub+1,
+               re_Oops_trace_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_trace, line, re_Oops_trace_pmatch,
+                       string);
+               if ((*string)[1] || (*string)[2]) {
+                       trace_line = 1;
+                       start = line + re_Oops_trace_pmatch[0].rm_eo;
+               }
+               else if ((*string)[5]) {
+                       trace_line = 2;         /* ppc */
+                       start = line + re_Oops_trace_pmatch[0].rm_eo;
+               }
+               else if (trace_line == 1 && (*string)[3])
+                       start = line + re_Oops_trace_pmatch[3].rm_so;
+               else if (trace_line == 2 && (*string)[6])       /* ppc */
+                       start = line + re_Oops_trace_pmatch[6].rm_so;
+               else
+                       trace_line = 0;
+       }
+       else
+               trace_line = 0;
+       if (trace_line)
+               return(start);
+       return(NULL);
+}
+
+/* Process a trace call line, extract addresses */
+static void Oops_trace_line(const char *line, const char *p, SYMBOL_SET *ss)
+{
+       char **string = NULL;
+       regex_t *pregex;
+       regmatch_t *pregmatch;
+       static const char procname[] = "Oops_trace_line";
+
+       /* ppc does not bracket its addresses */
+       if (isxdigit(*p)) {
+               pregex = &re_unbracketed_address;
+               pregmatch = re_unbracketed_address_pmatch;
+       }
+       else {
+               pregex = &re_bracketed_address;
+               pregmatch = re_bracketed_address_pmatch;
+       }
+
+       /* Loop over [un]?bracketed addresses */
+       while (regexec(pregex, p, pregex->re_nsub+1, pregmatch, 0) == 0) {
+               re_strings(pregex, p, pregmatch, &string);
+               add_symbol(ss, string[1], 'T', 1, "Trace:");
+               p += pregmatch[0].rm_eo;
+       }
+
+       if (*p && !strcmp(p, "...")) {
+               fprintf(stderr,
+                       "Warning garbage '%s' at end of trace line ignored "
+                       "by %s\n",
+                       p, procname);
+               ++warnings;
+       }
+       re_strings_free(pregex, &string);
+}
+
+/* Do pattern matching to decide if the line should be printed.  When reading a
+ * syslog containing multiple Oops, you need the intermediate data (registers,
+ * tss etc.) to go with the decoded text.  Sets text to the start of the useful
+ * text, after any prefix.  Note that any leading white space is treated as part
+ * of the prefix, later routines do not see any indentation.
+ */
+static int Oops_print(const char *line, const char **text, char ***string,
+                     int string_max)
+{
+       int i, print;
+       static int stack_line = 0, trace_line = 0;
+       static regex_t     re_Oops_prefix;
+       static regmatch_t *re_Oops_prefix_pmatch;
+       static regex_t     re_Oops_print;
+       static regmatch_t *re_Oops_print_pmatch;
+       static const char procname[] = "Oops_print";
+
+       *text = line;
+
+       /* Lines to be ignored.  For some reason the "amuse the user" print in
+        * some die_if_kernel routines causes regexec to run very slowly.
+        */
+
+       if (strstr(*text, "\\|/ ____ \\|/")  ||
+           strstr(*text, "\"@'/ ,. \\`@\"") ||
+           strstr(*text, "/_| \\__/ |_\\")  ||
+           strstr(*text, "   \\__U_/"))
+               return(1);      /* print but avoid regexec */
+
+       /* Prefixes to be ignored */
+       re_compile(&re_Oops_prefix,
+                       "^("                    /* start of line */
+                       "([^ ]{3} [ 0-9][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} "
+                         "[^ ]+ kernel: +)"    /* syslogd */
+                       "|(<[0-9]+>)"           /* kmsg */
+                       "|([ \t]+)"             /* leading white space */
+                       ")+"                    /* any prefixes, in any order */
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_prefix_pmatch);
+
+       re_string_check(re_Oops_prefix.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_prefix, *text, re_Oops_prefix.re_nsub+1,
+               re_Oops_prefix_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec prefix %d\n", procname, i);
+       if (i == 0)
+               *text += re_Oops_prefix_pmatch[0].rm_eo;  /* step over prefix */
+
+
+       /* Lots of possibilities.  Expand as required for all architectures.
+        *
+        * The order below is required to handle multiline outupt.
+        * string[2] is defined if the text is 'Stack from '.
+        * string[3] is defined if the text is 'Stack: '.
+        * string[4] is defined if the text might be a stack continuation.
+        * string[5] is defined if the text is 'Call Trace: '.
+        * string[6] is defined if the text might be a trace continuation.
+        * string[7] is the address part of the BRACKETED_ADDRESS.
+        *
+        * string[8] is defined if the text contains a version number.  No Oops
+        * report contains this as of 2.1.125 but IMHO it should be added.  If
+        * anybody wants to print a VERSION_nnnn line in their Oops, this code
+        * is ready.
+        *
+        * string[9] is defined if the text is 'Trace: ' (alpha).
+        * string[10] is defined if the text is 'Call backtrace:' (ppc).
+        */
+       re_compile(&re_Oops_print,
+       /* arch type */                                     /* Required order */
+                       "("                                             /*  1 */
+       /* i386 */      "^(Stack: )"                                    /*  2 */
+       /* m68k */      "|^(Stack from )"                               /*  3 */
+       /* various */   "|^([0-9a-fA-F]{4,})"                           /*  4 */
+       /* various */   "|^(Call Trace: )"                              /*  5 */
+       /* various */   "|^(" BRACKETED_ADDRESS ")"                     /* 6,7*/
+       /* various */   "|^(Version_[0-9]+)"                            /*  8 */
+       /* alpha */     "|^(Trace: )"                                   /*  9 */
+       /* ppc */       "|^(Call backtrace:)"                           /* 10 */
+
+                       /* order does not matter from here on */
+       
+       /* various */   "|(Unable to handle kernel)"
+       /* various */   "|^(Process .*stackpage=)"
+       /* various */   "|^(Call Trace:[ \t])"
+       /* various */   "|^(Code *:[ \t])"
+       /* various */   "|^(Kernel panic)"
+       /* various */   "|^(In swapper task)"
+       /* various */   "|(Aiee)"      /* anywhere in text is a bad sign (TM) */
+       /* various */   "|(die_if_kernel)"      /* ditto */
+
+       /* i386 2.0 */  "|^(Corrupted stack page)"
+       /* i386 */      "|^(invalid operand: )"
+       /* i386 */      "|^(Oops: )"
+       /* i386 */      "|^(Cpu: +[0-9])"
+       /* i386 */      "|^(current->tss)"
+       /* i386 */      "|^(\\*pde +=)"
+       /* i386 */      "|^(EIP: )"
+       /* i386 */      "|^(EFLAGS: )"
+       /* i386 */      "|^(eax: )"
+       /* i386 */      "|^(esi: )"
+       /* i386 */      "|^(ds: )"
+
+       /* m68k */      "|^(pc=)"
+       /* m68k */      "|^(68060 access)"
+       /* m68k */      "|^(Exception at )"
+       /* m68k */      "|^(PC: )"
+       /* m68k */      "|^(d[04]: )"
+       /* m68k */      "|^(Frame format=)"
+       /* m68k */      "|^(wb [0-9] stat)"
+       /* m68k */      "|^(push data: )"
+       /* m68k */      "|^(baddr=)"
+       /* any other m68K lines to print? */
+
+       /* sparc */     "|(\\([0-9]\\): Oops )"
+       /* sparc */     "|(: memory violation)"
+       /* sparc */     "|(: Exception at)"
+       /* sparc */     "|(: Arithmetic fault)"
+       /* sparc */     "|(: Instruction fault)"
+       /* sparc */     "|(: arithmetic trap)"
+       /* sparc */     "|^(Bad unaligned kernel)"
+       /* sparc */     "|^(Forwarding unaligned exception)"
+       /* sparc */     "|^(: unhandled unaligned exception)"
+       /* sparc */     "|(: unaligned trap)"
+       /* sparc */     "|^(<sc)"
+       /* sparc */     "|^(pc *=)"
+       /* sparc */     "|^(r[0-9]+ *=)"
+       /* sparc */     "|^(gp *=)"
+       /* any other sparc lines to print? */
+
+       /* alpha */     "|^(tsk->)"
+       /* alpha   die_if_kernel has no fixed text, identify by (pid): text. */
+       /* alpha */     "|^(.*\\([0-9]+\\): "
+                          /* Somebody has been playful with the texts.  */
+                          "((Whee)|(Oops)|(Kernel)|(.*Penguin)|(BOGUS))"
+                         ")"
+       /* alpha */     "|^(PSR: )"
+       /* alpha */     "|^(g0: )"
+       /* alpha */     "|^(o0: )"
+       /* alpha */     "|^(l0: )"
+       /* alpha */     "|^(i0: )"
+       /* alpha */     "|^(Instruction DUMP: )"
+       /* any other alpha lines to print? */
+
+       /* ppc */       "|^(MSR: )"
+       /* ppc */       "|^(TASK = )"
+       /* ppc */       "|^(last math )"
+       /* ppc */       "|^(GPR[0-9]+: )"
+       /* ppc */       "|(kernel pc )"
+       /* ppc */       "|(trap at PC: )"
+       /* ppc */       "|(bad area pc )"
+       /* ppc */       "|(NIP: )"
+       /* any other ppc lines to print? */
+
+       /* MIPS */      "|^(\\$[0-9 ]+:)"
+       /* MIPS */      "|^(epc )"
+       /* MIPS */      "|^(Status:)"
+       /* MIPS */      "|^(Cause :)"
+       /* MIPS */      "|( ra *=)"
+       /* any other MIPS lines to print? */
+
+                       ")",
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_print_pmatch);
+
+       re_string_check(re_Oops_print.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_print, *text, re_Oops_print.re_nsub+1,
+               re_Oops_print_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       print = 0;
+       if (i == 0) {
+               re_strings(&re_Oops_print, *text, re_Oops_print_pmatch,
+                       string);
+               print = 1;
+               /* Handle multiline messages, messy */
+               if (!(*string)[2] && !(*string)[3] && !(*string)[4])
+                       stack_line = 0;
+               else if ((*string)[2] || (*string)[3])
+                       stack_line = 1;
+               else if (stack_line && !(*string)[4]) {
+                       print = 0;
+                       stack_line = 0;
+               }
+               if (!(*string)[5] && !(*string)[6] && !(*string)[9])
+                       trace_line = 0;
+               else if ((*string)[5] || (*string)[9] || (*string)[10])
+                       trace_line = 1;
+               else if (stack_line && !(*string)[6]) {
+                       print = 0;
+                       trace_line = 0;
+               }
+               if ((*string)[8])
+                       add_Version((*string)[8]+8, "Oops");
+       }
+       return(print);
+}
+
+/* Look for the Code: line.  Returns start of the code bytes. */
+static const char *Oops_code(const char *line, char ***string, int string_max)
+{
+       int i;
+       static regex_t     re_Oops_code;
+       static regmatch_t *re_Oops_code_pmatch;
+       static const char procname[] = "Oops_code";
+
+       /* Oops 'Code: ' hopefully followed by at least one hex code.  sparc
+        * brackets the PC in '<' and '>'.
+        */
+       re_compile(&re_Oops_code,
+                       "^("                                            /*  1 */
+       /* sparc */       "(Instruction DUMP)"                          /*  2 */
+       /* various */     "|(Code *)"                                   /*  3 */
+                       ")"
+                       ":[ \t]+"
+                       "("                                             /*  4 */
+                         "(general protection.*)"
+                         "|(<[0-9]+>)"
+                         "|((<?[0-9a-fA-F]+>?[ \t]*)+)"
+                       ")"
+                       "(.*)$"                         /* trailing garbage */
+                       ,
+               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
+               &re_Oops_code_pmatch);
+
+       re_string_check(re_Oops_code.re_nsub+1, string_max, procname);
+       i = regexec(&re_Oops_code, line, re_Oops_code.re_nsub+1,
+               re_Oops_code_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i == 0) {
+               re_strings(&re_Oops_code, line, re_Oops_code_pmatch,
+                       string);
+               if ((*string)[re_Oops_code.re_nsub] &&
+                   *((*string)[re_Oops_code.re_nsub])) {
+                       fprintf(stderr,
+                               "Warning: trailing garbage ignored on Code: "
+                               "line\n"
+                               "  Text: '%s'\n"
+                               "  Garbage: '%s'\n",
+                               line, (*string)[re_Oops_code.re_nsub]);
+                       ++warnings;
+               }
+               return((*string)[4]);
+       }
+       return(NULL);
+}
+
+/******************************************************************************/
+/*                      End architecture sensitive code                       */
+/******************************************************************************/
+
+/* Decode the Oops Code: via objdump*/
+static void Oops_decode(const unsigned char* code_text, elf_addr_t eip,
+                       SYMBOL_SET *ss, char ***string, int string_max)
+{
+       FILE *f;
+       char *file, *line = NULL, code[CODE_SIZE];
+       int size = 0, adjust;
+       static char const procname[] = "Oops_decode";
+
+       if (debug)
+               fprintf(stderr, "DEBUG: %s\n", procname);
+       /* text to binary */
+       if (!Oops_code_values(code_text, code, &adjust, string, string_max))
+               return;
+       /* binary to same format as ksymoops */
+       if (!(file = Oops_code_to_file(code, CODE_SIZE)))
+               return;
+       /* objdump the pseudo object */
+       if (!(f = Oops_objdump(file)))  
+               return;
+       while (fgets_local(&line, &size, f, procname)) {
+               if (debug > 1)
+                       fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
+               Oops_decode_one(ss, line, eip, adjust);
+       }
+       pclose_local(f, procname);      /* opened in Oops_objdump */
+       free(line);
+       if (unlink(file)) {
+               fprintf(stderr, "%s could not unlink %s", prefix, file);
+               perror(" ");
+       }
+}
+
+/* Reached the end of an Oops report, format the extracted data. */
+static void Oops_format(const SYMBOL_SET *ss_format)
+{
+       int i;
+       SYMBOL *s;
+       static const char procname[] = "Oops_format";
+
+       if (debug)
+               fprintf(stderr, "DEBUG: %s\n", procname);
+
+       compare_Version();      /* Oops might have a version one day */
+       printf("\n");
+       for (s = ss_format->symbol, i = 0; i < ss_format->used; ++i, ++s) {
+               /* For type C data, print Code:, address, map, "name" (actually
+                * the text of an objdump line).  For other types print name,
+                * address, map.
+                */
+               if (s->type == 'C')
+                       printf("Code:  %s %-30s %s\n",
+                               format_address(s->address),
+                               map_address(&ss_merged, s->address),
+                               s->name);
+               else
+                       printf("%s %s %s\n",
+                               s->name,
+                               format_address(s->address),
+                               map_address(&ss_merged, s->address));
+       }
+       printf("\n");
+}
+
+/* Select next Oops input file */
+static FILE *Oops_next_file(int *filecount, char * const **filename)
+{
+       static FILE *f = NULL;
+       static const char procname[] = "Oops_next_file";
+       static int first_file = 1;
+
+       if (first_file) {
+               f = stdin;
+               first_file = 0;
+       }
+       while (*filecount) {
+               if (f)
+                       fclose_local(f, procname);
+               f = NULL;
+               if (regular_file(**filename, procname))
+                       f = fopen_local(**filename, "r", procname);
+               if (f) {
+                       if (debug)
+                               fprintf(stderr,
+                                       "DEBUG: reading Oops report "
+                                       "from %s\n", **filename);
+               }
+               ++*filename;
+               --*filecount;
+               if (f)
+                       return(f);
+       }
+       return(f);
+}
+
+/* Read the Oops report */
+#define MAX_STRINGS 300        /* Maximum strings in any Oops re */
+void Oops_read(int filecount, char * const *filename)
+{
+       char *line = NULL, **string = NULL;
+       const char *start, *text;
+       int i, size = 0, lineno = 0, lastprint = 0;
+       elf_addr_t eip = 0;
+       FILE *f;
+       SYMBOL_SET ss_format;
+       static const char procname[] = "Oops_read";
+
+       ss_init(&ss_format, "Oops log data");
+
+       if (!filecount && isatty(0))
+               printf("Reading Oops report from the terminal\n");
+
+       string = malloc(MAX_STRINGS*sizeof(*string));
+       if (!string)
+               malloc_error(procname);
+       memset(string, '\0', MAX_STRINGS*sizeof(*string));
+
+       do {
+               if (!(f = Oops_next_file(&filecount, &filename)))
+                       continue;
+               while (fgets_local(&line, &size, f, procname)) {
+                       if (debug > 2)
+                               fprintf(stderr,
+                                       "DEBUG: %s - %s\n", procname, line);
+                       ++lineno;
+                       if (Oops_print(line, &text, &string, MAX_STRINGS)) {
+                               puts(line);
+                               lastprint = lineno;
+                       }
+                       if ((start = Oops_eip(text, &string, MAX_STRINGS)))
+                               Oops_set_eip(start, &eip, &ss_format);
+                       if ((start = Oops_ra(text, &string, MAX_STRINGS)))
+                               Oops_set_ra(start, &ss_format);
+                       if ((start = Oops_trace(text, &string, MAX_STRINGS)))
+                               Oops_trace_line(text, start, &ss_format);
+                       if ((start = Oops_code(text, &string, MAX_STRINGS))) {
+                               Oops_decode(start, eip, &ss_format,
+                                       &string, MAX_STRINGS);
+                               Oops_format(&ss_format);
+                               ss_free(&ss_format);
+                       }
+                       /* More than 5 (arbitrary) lines which were not printed
+                        * and there is some saved data, assume we missed the
+                        * Code: line.
+                        */
+                       if (ss_format.used && lineno > lastprint+5) {
+                               fprintf(stderr,
+                                       "Warning, Code line not seen, dumping "
+                                       "what data is available\n");
+                               ++warnings;
+                               Oops_format(&ss_format);
+                               ss_free(&ss_format);
+                       }
+               }
+               if (ss_format.used) {
+                       fprintf(stderr,
+                               "Warning, Code line not seen, dumping "
+                               "what data is available\n");
+                       ++warnings;
+                       Oops_format(&ss_format);
+                       ss_free(&ss_format);
+               }
+       } while (filecount != 0);
+
+       for (i = 0; i < sizeof(string); ++i) {
+               free(string[i]);
+               string[i] = NULL;
+       }
+       free(line);
+}
diff --git a/scripts/ksymoops-0.6/patches/README b/scripts/ksymoops-0.6/patches/README
new file mode 100644 (file)
index 0000000..7727d8e
--- /dev/null
@@ -0,0 +1,15 @@
+An ad-hoc collection of patches to the Linux kernel and related
+utilities, to make the best use of ksymoops.
+
+Most of the kernel patches are to extend the information logged on an
+Oops, some architectures currently (2.1.126) do not provide full
+diagnostics.  Hopefully these patches will be integrated into the
+kernel tree in future.  ksymoops will still run without these patches
+but will provide degraded output.
+
+mips    - Kernel patch by Ulf Carlsson <ulfc@bun.falkenberg.se> to
+          provide full diagnostics on a mips Oops.
+
+ppc     - Kernel patch by "Ryan Nielsen" <ran@krazynet.com> to provide
+          full diagnostics on a ppc Oops.
+
diff --git a/scripts/ksymoops-0.6/patches/mips b/scripts/ksymoops-0.6/patches/mips
new file mode 100644 (file)
index 0000000..ec0b0b6
--- /dev/null
@@ -0,0 +1,167 @@
+--- linux/arch/mips/kernel/traps.c-orig        Thu Oct 29 17:23:19 1998
++++ linux/arch/mips/kernel/traps.c     Fri Oct 30 13:25:21 1998
+@@ -6,6 +6,7 @@
+  *
+  * Copyright 1994, 1995, 1996, 1997, 1998 by Ralf Baechle
+  * Modified for R3000 by Paul M. Antoine, 1995, 1996
++ * Complete output from die() by Ulf Carlsson, 1998
+  */
+ #include <linux/config.h>
+ #include <linux/init.h>
+@@ -80,50 +81,61 @@
+  * This routine abuses get_user()/put_user() to reference pointers
+  * with at least a bit of error checking ...
+  */
+-void show_registers(char * str, struct pt_regs * regs, long err)
++void show_stack(unsigned int *sp)
+ {
+-      int     i;
+-      int     *stack;
+-      u32     *sp, *pc, addr, module_start, module_end;
+-      extern  char start_kernel, _etext;
++      int i;
++      unsigned int *stack;
+-      sp = (u32 *)regs->regs[29];
+-      pc = (u32 *)regs->cp0_epc;
++      stack = sp;
++      i = 0;
+-      show_regs(regs);
++      printk("Stack:");
++      while ((unsigned long) stack & (PAGE_SIZE - 1)) {
++              unsigned long stackdata;
+-      /*
+-       * Dump the stack
+-       */
+-      printk("Process %s (pid: %ld, stackpage=%08lx)\nStack: ",
+-              current->comm, current->pid, (unsigned long)current);
+-      for(i=0;i<5;i++)
+-              printk("%08x ", *sp++);
+-      stack = (int *) sp;
++              if (__get_user(stackdata, stack++)) {
++                      printk(" (Bad stack address)");
++                      break;
++              }
+-      for(i=0; i < kstack_depth_to_print; i++) {
+-              unsigned int stackdata;
++              printk(" %08lx", stackdata);
+-              if (((u32) stack & (PAGE_SIZE -1)) == 0)
+-                      break;
+-              if (i && ((i % 8) == 0))
+-                      printk("\n       ");
+-              if (get_user(stackdata, stack++) < 0) {
+-                      printk("(Bad stack address)");
++              if (++i > 40) {
++                      printk(" ...");
+                       break;
+               }
+-              printk("%08x ", stackdata);
++
++              if (i % 8 == 0)
++                      printk("\n      ");
+       }
+-      printk("\nCall Trace: ");
+-      stack = (int *)sp;
+-      i = 1;
++}
++
++void show_trace(unsigned int *sp)
++{
++      int i;
++      unsigned int *stack;
++      unsigned long kernel_start, kernel_end;
++      unsigned long module_start, module_end;
++      extern char _stext, _etext;
++
++      stack = sp;
++      i = 0;
++
++      kernel_start = (unsigned long) &_stext;
++      kernel_end = (unsigned long) &_etext;
+       module_start = VMALLOC_START;
+       module_end = module_start + MODULE_RANGE;
+-      while (((unsigned long)stack & (PAGE_SIZE -1)) != 0) {
+-              if (get_user(addr, stack++) < 0) {
+-                      printk("(Bad address)\n");
++
++      printk("\nCall Trace:");
++
++      while ((unsigned long) stack & (PAGE_SIZE -1)) {
++              unsigned long addr;
++
++              if (__get_user(addr, stack++)) {
++                      printk(" (Bad stack address)\n");
+                       break;
+               }
++
+               /*
+                * If the address is either in the text segment of the
+                * kernel, or in the region which contains vmalloc'ed
+@@ -132,26 +144,33 @@
+                * down the cause of the crash will be able to figure
+                * out the call path that was taken.
+                */
+-              if (((addr >= (u32) &start_kernel) &&
+-                   (addr <= (u32) &_etext)) ||
+-                  ((addr >= module_start) && (addr <= module_end))) {
+-                      if (i && ((i % 8) == 0))
+-                              printk("\n       ");
+-                      printk("%08x ", addr);
+-                      i++;
++
++              if ((addr >= kernel_start && addr < kernel_end) ||
++                  (addr >= module_start && addr < module_end)) { 
++
++                      printk(" [<%08lx>]", addr);
++                      if (++i > 40) {
++                              printk(" ...");
++                              break;
++                      }
+               }
+       }
++}
+-      printk("\nCode : ");
+-      if ((KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) &&
+-          (((unsigned long) pc & 3) == 0))
+-      {
+-              for(i=0;i<5;i++)
+-                      printk("%08x ", *pc++);
+-              printk("\n");
++void show_code(unsigned int *pc)
++{
++      long i;
++
++      printk("\nCode:");
++
++      for(i = -3 ; i < 6 ; i++) {
++              unsigned long insn;
++              if (__get_user(insn, pc + i)) {
++                      printk(" (Bad address in epc)\n");
++                      break;
++              }
++              printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
+       }
+-      else
+-              printk("(Bad address in epc)\n");
+ }
+ void die(const char * str, struct pt_regs * regs, unsigned long err)
+@@ -162,6 +181,12 @@
+       console_verbose();
+       printk("%s: %04lx\n", str, err & 0xffff);
+       show_regs(regs);
++      printk("Process %s (pid: %ld, stackpage=%08lx)\n",
++              current->comm, current->pid, (unsigned long) current);
++      show_stack((unsigned int *) regs->regs[29]);
++      show_trace((unsigned int *) regs->regs[29]);
++      show_code((unsigned int *) regs->cp0_epc);
++      printk("\n");
+       do_exit(SIGSEGV);
+ }
+
diff --git a/scripts/ksymoops-0.6/patches/ppc b/scripts/ksymoops-0.6/patches/ppc
new file mode 100644 (file)
index 0000000..5edecf4
--- /dev/null
@@ -0,0 +1,67 @@
+--- linux/arch/ppc/kernel/process.c    1998/10/11 17:47:23     1.67
++++ linux/arch/ppc/kernel/process.c    1998/11/02 03:11:28
+@@ -196,6 +198,19 @@
+       _enable_interrupts(s);
+ }
++void instruction_dump (unsigned long *pc)
++{
++      int i;
++
++      if((((unsigned long) pc) & 3))
++                return;
++
++      printk("Instruction DUMP:");
++      for(i = -3; i < 6; i++)
++              printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
++      printk("\n");
++}
++
+ void show_regs(struct pt_regs * regs)
+ {
+       int i;
+--- linux/arch/ppc/kernel/traps.c      1998/05/05 19:18:53     1.21
++++ linux/arch/ppc/kernel/traps.c      1998/11/02 03:11:36
+@@ -79,6 +79,7 @@
+               debugger(regs);
+ #endif
+               print_backtrace((unsigned long *)regs->gpr[1]);
++              instruction_dump((unsigned long *)regs->nip);
+               panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+       }
+       force_sig(signr, current);
+@@ -126,6 +127,7 @@
+               debugger(regs);
+ #endif
+               print_backtrace((unsigned long *)regs->gpr[1]);
++              instruction_dump((unsigned long *)regs->nip);
+               panic("machine check");
+       }
+       _exception(SIGSEGV, regs);      
+@@ -219,6 +221,7 @@
+ #endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
++      instruction_dump((unsigned long *)regs->nip);
+       panic("kernel stack overflow");
+ }
+--- linux/arch/ppc/mm/fault.c  1998/10/06 03:13:19     1.28
++++ linux/arch/ppc/mm/fault.c  1998/11/02 03:11:36
+@@ -89,6 +89,7 @@
+                       printk("page fault in interrupt handler, addr=%lx\n",
+                              address);
+                       show_regs(regs);
++                      instruction_dump((unsigned long *)regs->nip);
+ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+                       if (debugger_kernel_faults)
+                               debugger(regs);
+@@ -174,6 +175,7 @@
+       /* kernel has accessed a bad area */
+       show_regs(regs);
+       print_backtrace( (unsigned long *)regs->gpr[1] );
++      instruction_dump((unsigned long *)regs->nip);
+ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       if (debugger_kernel_faults)
+               debugger(regs);
+
diff --git a/scripts/ksymoops-0.6/re.c b/scripts/ksymoops-0.6/re.c
new file mode 100644 (file)
index 0000000..9c65832
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+       re.c.
+
+       Regular expression processing for ksymoops.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       PPC trace addresses are not bracketed, add new re.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <malloc.h>
+#include <string.h>
+
+/* Compile a regular expression */
+void re_compile(regex_t *preg, const char *regex, int cflags,
+               regmatch_t **pmatch)
+{
+       int i, l;
+       char *p;
+       static char const procname[] = "re_compile";
+
+       if (preg->re_nsub)
+               return;         /* already compiled */
+
+       if (debug)
+               fprintf(stderr, "DEBUG: %s '%s'", procname, regex);
+       if ((i = regcomp(preg, regex, cflags))) {
+               l = regerror(i, preg, NULL, 0);
+               ++l;    /* doc is ambiguous, be safe */
+               p = malloc(l);
+               if (!p)
+                       malloc_error("regerror text");
+               regerror(i, preg, p, l);
+               fprintf(stderr,
+                       "%s: fatal %s error on '%s' - %s\n",
+                       prefix, procname, regex, p);
+               exit(2);
+       }
+       if (debug)
+               fprintf(stderr, " %d sub expression(s)\n", preg->re_nsub);
+       /* [0] is entire match, [1] is first substring */
+       *pmatch = malloc((preg->re_nsub+1)*sizeof(**pmatch));
+       if (!*pmatch)
+               malloc_error("pmatch");
+
+}
+
+/* Compile common regular expressions */
+void re_compile_common(void)
+{
+
+       /* nm: address, type, symbol */
+       re_compile(&re_nm,
+               "^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)$",
+               REG_NEWLINE|REG_EXTENDED,
+               &re_nm_pmatch);
+
+       /* bracketed address preceded by optional white space */
+       re_compile(&re_bracketed_address,
+               "^[ \t]*" BRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED,
+               &re_bracketed_address_pmatch);
+
+       /* unbracketed address preceded by optional white space */
+       re_compile(&re_unbracketed_address,
+               "^[ \t*]*" UNBRACKETED_ADDRESS,
+               REG_NEWLINE|REG_EXTENDED,
+               &re_unbracketed_address_pmatch);
+
+}
+
+/* Split text into the matching re substrings - Perl is so much easier :).
+ * Each element of *string is set to a malloced copy of the substring or
+ * NULL if the substring did not match (undef).  A zero length substring match
+ * is represented by a zero length **string.
+ */
+void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
+               char ***string)
+{
+       int i;
+       if (!*string) {
+               *string = malloc((preg->re_nsub+1)*sizeof(**string));
+               if (!*string)
+                       malloc_error("re_strings base");
+               for (i = 0; i < preg->re_nsub+1; ++i)
+                       (*string)[i] = NULL;
+       }
+       for (i = 0; i < preg->re_nsub+1; ++i) {
+               if (debug > 4)
+                       fprintf(stderr,
+                               "DEBUG: re_string %d offsets %d %d",
+                               i, pmatch[i].rm_so, pmatch[i].rm_eo);
+               if (pmatch[i].rm_so == -1) {
+                       /* no match for this sub expression */
+                       free((*string)[i]);
+                       (*string)[i] = NULL;
+                       if (debug > 4)
+                               fprintf(stderr, " (undef)\n");
+               }
+               else {
+                       int l = pmatch[i].rm_eo - pmatch[i].rm_so + 1;
+                       char *p;
+                       p = malloc(l);
+                       if (!p)
+                               malloc_error("re_strings");
+                       strncpy(p, text+pmatch[i].rm_so, l-1);
+                       *(p+l-1) = '\0';
+                       (*string)[i] = p;
+                       if (debug > 4)
+                               fprintf(stderr, " '%s'\n", p);
+               }
+       }
+}
+
+/* Free the matching re substrings */
+void re_strings_free(const regex_t *preg, char ***string)
+{
+       if (*string) {
+               int i;
+               for (i = 0; i < preg->re_nsub+1; ++i)
+                       free((*string)[i]);
+               free(*string);
+               *string = NULL;
+       }
+}
+
+/* Check that there are enough strings for an re */
+void re_string_check(int need, int available, const char *msg)
+{
+       if (need > available) {
+               fprintf(stderr,
+                       "%s: fatal not enough re_strings in %s.  "
+                       "Need %d, available %d\n",
+                       prefix, msg, need, available);
+               exit(2);
+       }
+}
diff --git a/scripts/ksymoops-0.6/symbol.c b/scripts/ksymoops-0.6/symbol.c
new file mode 100644 (file)
index 0000000..00c6f4e
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+       symbol.c.
+
+       Symbol handling routines for ksymoops.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       Tue Nov  3 02:31:01 EST 1998
+       Version 0.6
+       Fix end of code calculation.
+
+       Wed Oct 28 13:47:23 EST 1998
+       Version 0.4
+       Split into separate sources.
+ */
+
+#include "ksymoops.h"
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Initialise a symbol source */
+void ss_init(SYMBOL_SET *ss, const char *msg)
+{
+       memset(ss, '\0', sizeof(*ss));
+       ss->source = strdup(msg);
+       if (!ss->source)
+               malloc_error(msg);
+}
+
+/* Free dynamic data from a symbol source */
+void ss_free(SYMBOL_SET *ss)
+{
+       int i;
+       SYMBOL *s;
+       for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
+               free(s->name);
+       free(ss->symbol);
+       free(ss->source);
+       memset(ss, '\0', sizeof(*ss));
+}
+
+/* Initialise common symbol sets */
+void ss_init_common(void)
+{
+       ss_init(&ss_Version, "Version_");
+}
+
+/* Find a symbol name in a symbol source.  Brute force ascending order search,
+ * no hashing.  If start is not NULL, it contains the starting point for the
+ * scan and is updated to point to the found entry.  If the entry is not found,
+ * return NULL with start pointing to the next highest entry.
+ * NOTE: Assumes that ss is sorted by name.
+ */
+SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
+{
+       int i, l;
+       SYMBOL *s;
+       for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
+               if ((l = strcmp(symbol, s->name)) == 0) {
+                       if (start)
+                               *start = i;
+                       return(s);
+               }
+               if (l < 0)
+                       break;
+       }
+       if (start)
+               *start = i;
+       return NULL;
+}
+
+/* Find an address in a symbol source.  Brute force ascending order search, no
+ * hashing.  If start is not NULL, it contains the starting point for the scan
+ * and is updated to point to the found entry.  If the entry is not found,
+ * return NULL with start pointing to the next highest entry.
+ * NOTE: Assumes that ss is sorted by address.
+ */
+static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
+                           const elf_addr_t address, int *start)
+{
+       int i;
+       SYMBOL *s;
+       for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
+               if (address > s->address)
+                       continue;
+               else if (address == s->address) {
+                       if (start)
+                               *start = i;
+                       return(s);
+               }
+               else
+                       break;
+       }
+       if (start)
+               *start = i;
+       return NULL;
+}
+
+/* Add a symbol to a symbol set, address in binary */
+void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
+                 const char type, const char keep, const char *symbol)
+{
+       int i;
+       char **string = NULL;
+       SYMBOL *s;
+       static regex_t     re_symbol_ver;
+       static regmatch_t *re_symbol_ver_pmatch;
+       static const char procname[] = "add_symbol_n";
+
+       /* Strip out any trailing symbol version _Rxxxxxxxx. */
+       re_compile(&re_symbol_ver,
+               "^(.*)_R[0-9a-fA-F]{8,}$",
+               REG_NEWLINE|REG_EXTENDED,
+               &re_symbol_ver_pmatch);
+
+       i = regexec(&re_symbol_ver, symbol,
+                   re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
+       if (i == 0)
+               re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
+                       &string);
+
+       if (debug > 3)
+               fprintf(stderr, "DEBUG: %s %s %s '%c' %d '%s'\n",
+                       procname, ss->source, format_address(address),
+                       type, keep, i == 0 ? string[1] : symbol);
+       if (ss->used > ss->alloc) {
+               fprintf(stderr,
+                       "%s: fatal %s ss %s used (%d) > alloc (%d)\n",
+                       procname, prefix, ss->source, ss->used, ss->alloc);
+               exit(2);
+       }
+       if (ss->used == ss->alloc) {
+               /* increase by 20% or 10, whichever is larger, arbitrary */
+               int newsize = ss->alloc*120/100;
+               if (newsize < ss->alloc+10)
+                       newsize = ss->alloc+10;
+               if (debug > 3)
+                       fprintf(stderr,
+                               "DEBUG: %s increasing %s from %d to %d "
+                               "entries\n",
+                               procname, ss->source, ss->alloc, newsize);
+               ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
+               if (!ss->symbol)
+                       malloc_error("realloc ss");
+               ss->alloc = newsize;
+       }
+       s = ss->symbol+ss->used;
+       if (i == 0) {
+               s->name = string[1];
+               string[1] = NULL;       /* don't free this one */
+       }
+       else {
+               s->name = strdup(symbol);
+               if (!s->name)
+                       malloc_error("strdup symbol");
+       }
+       s->type = type;
+       s->keep = keep;
+       s->address = address;
+       ++ss->used;
+       re_strings_free(&re_symbol_ver, &string);
+}
+
+/* Add a symbol to a symbol set, address in character */
+void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
+               const char keep, const char *symbol)
+{
+       elf_addr_t a;
+       static char const procname[] = "add_symbol";
+       errno = 0;
+       a = strtoul(address, NULL, 16);
+       if (errno) {
+               fprintf(stderr,
+                       "%s: %s address '%s' is in error",
+                       prefix, procname, address);
+               perror(" ");
+               ++errors;
+       }
+       add_symbol_n(ss, a, type, 1, symbol);
+}
+
+/* Map an address to symbol, offset and length, address in binary */
+char *map_address(const SYMBOL_SET *ss, const elf_addr_t address)
+{
+       int i = 0, l;
+       SYMBOL *s;
+       static char *map = NULL;
+       static int size = 0;
+       static const char procname[] = "map_address_n";
+
+       if (debug > 2)
+               fprintf(stderr, "DEBUG: %s %s %s\n",
+                       procname, ss->source, format_address(address));
+       s = find_symbol_address(ss, address, &i);
+       if (!s && --i >= 0)
+               s = ss->symbol+i;       /* address is between s and s+1 */
+                       
+       /* Extra map text is always < 100 bytes */
+       if (s)
+               l = strlen(s->name) + 100;
+       else
+               l = 100;
+       if (l > size) {
+               map = realloc(map, l);
+               if (!map)
+                       malloc_error(procname);
+               size = l;
+       }
+       if (!s) {
+               if (ss->used == 0)
+                       snprintf(map, size, "No symbols available");
+               else
+                       snprintf(map, size, "Before first symbol");
+       }
+       else if ((i+1) >= ss->used) {
+               /* Somewhere past last symbol.  Length of last section of code
+                * is unknown, arbitrary cutoff at 32K.
+                */
+               elf_addr_t offset = address - s->address;
+               if (offset > 32768)
+                       snprintf(map, size, "<END_OF_CODE+%lx/????>", offset);
+               else
+                       snprintf(map, size, "<%s+%lx/????>", s->name, offset);
+       }
+       else
+               snprintf(map, size,
+                       "<%s+%lx/%lx>",
+                       s->name, address - s->address,
+                       (s+1)->address - s->address);
+       return(map);
+}
+
+/* After sorting, obsolete symbols are at the top.  Delete them. */
+static void ss_compress(SYMBOL_SET *ss)
+{
+       int i, j;
+       SYMBOL *s;
+       static const char procname[] = "ss_compress";
+
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: %s on table %s, before %d ",
+                       procname, ss->source, ss->used);
+       for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
+               if (!s->keep) {
+                       for (j = i; j < ss->used; ++j, ++s) {
+                               if (s->keep) {
+                                       fprintf(stderr,
+                                               "%s: fatal %s table %s is not "
+                                               "sorted\n",
+                                               prefix, procname, ss->source);
+                                       exit(2);
+                               }
+                       }
+                       break;
+               }
+       }
+       for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s)
+               free(s->name);
+       ss->used = i;
+       if (debug > 1)
+               fprintf(stderr, "after %d\n", ss->used);
+}
+
+static int ss_compare_atn(const void *a, const void *b)
+{
+       SYMBOL *c = (SYMBOL *) a;
+       SYMBOL *d = (SYMBOL *) b;
+       int i;
+
+       /* obsolete symbols to the top */
+       if (c->keep != d->keep)
+               return(d->keep - c->keep);
+       if (c->address > d->address)
+               return(1);
+       if (c->address < d->address)
+               return(-1);
+       if (c->type > d->type)
+               return(1);
+       if (c->type < d->type)
+               return(-1);
+       if ((i = strcmp(c->name, d->name)))
+               return(i);
+       return(0);
+}
+
+/* Sort a symbol set by address, type and name */
+void ss_sort_atn(SYMBOL_SET *ss)
+{
+       if (debug)
+               fprintf(stderr, "DEBUG: sorting symbols for %s (atn)\n",
+                       ss->source);
+       qsort((char *) ss->symbol, (unsigned) ss->used,
+               sizeof(*(ss->symbol)), ss_compare_atn);
+       ss_compress(ss);
+}
+
+static int ss_compare_na(const void *a, const void *b)
+{
+       SYMBOL *c = (SYMBOL *) a;
+       SYMBOL *d = (SYMBOL *) b;
+       int i;
+
+       /* obsolete symbols to the top */
+       if (c->keep != d->keep)
+               return(d->keep - c->keep);
+       if ((i = strcmp(c->name, d->name)))
+               return(i);
+       if (c->address > d->address)
+               return(1);
+       if (c->address < d->address)
+               return(-1);
+       return(0);
+}
+
+/* Sort a symbol set by name and address, drop duplicates.  There should be
+ * no duplicates but I have seen duplicates in ksyms on 2.0.35.
+ */
+void ss_sort_na(SYMBOL_SET *ss)
+{
+       int i;
+       SYMBOL *s;
+       if (debug)
+               fprintf(stderr, "DEBUG: sorting symbols for %s (na)\n",
+                       ss->source);
+       qsort((char *) ss->symbol, (unsigned) ss->used,
+               sizeof(*(ss->symbol)), ss_compare_na);
+       ss_compress(ss);
+       s = ss->symbol;
+       for (i = 0; i < ss->used-1; ++i) {
+               if (strcmp(s->name, (s+1)->name) == 0 &&
+                   s->address == (s+1)->address) {
+                       if (s->type != ' ')
+                               (s+1)->keep = 0;
+                       else
+                               s->keep = 0;
+               }
+               ++s;
+       }
+       qsort((char *) ss->symbol, (unsigned) ss->used,
+               sizeof(*(ss->symbol)), ss_compare_na);
+       ss_compress(ss);
+}
+
+/* Copy a symbol set, including all its strings */
+SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
+{
+       SYMBOL_SET *ssc;
+       if (debug > 3)
+               fprintf(stderr,
+                       "DEBUG: ss_copy %s\n", ss->source);
+       ssc = malloc(sizeof(*ssc));
+       if (!ssc)
+               malloc_error("copy ssc");
+       ss_init(ssc, ss->source);
+       ssc->used = ss->used;
+       ssc->alloc = ss->used;  /* shrink the copy */
+       ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
+       if (!(ssc->symbol))
+               malloc_error("copy ssc symbols");
+       memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
+       return(ssc);
+}
+
+/* Convert version number to major, minor string.  */
+static const char *format_Version(elf_addr_t Version)
+{
+       static char string[12]; /* 255.255.255\0 worst case */
+       snprintf(string, sizeof(string), "%d.%d.%d",
+               (Version >> 16) & 0xff,
+               (Version >> 8) & 0xff,
+               (Version) & 0xff);
+       return(string);
+}
+
+/* Save version number.  The "address" is the version number, the "symbol" is
+ * the source of the version.
+ */
+void add_Version(const char *version, const char *source)
+{
+       static char const procname[] = "add_Version";
+       int i = atoi(version);
+       if (debug > 1)
+               fprintf(stderr, "DEBUG: %s %s %s %s\n",
+                       procname, source, version, format_Version(i));
+       add_symbol_n(&ss_Version, i, 'V', 1, source);
+}
+
+/* Extract Version_ number from a symbol set and save it.  */
+void extract_Version(SYMBOL_SET *ss)
+{
+       int i = 0;
+       SYMBOL *s;
+
+       s = find_symbol_name(ss, "Version_", &i);
+       if (!s && i < ss->used)
+               s = ss->symbol+i;       /* first symbol after "Version_" */
+       if (!s || strncmp(s->name, "Version_", 8))
+               return;
+       add_Version(s->name+8, ss->source);
+}
+
+/* Compare all extracted Version numbers.  Silent unless there is a problem. */
+void compare_Version(void)
+{
+       int i = 0;
+       SYMBOL *s, *s0;
+       static int prev_used = 0;
+
+       if (!ss_Version.used)
+               return;
+       /* Only check if the Version table has changed in size */
+       if (prev_used == ss_Version.used)
+               return;
+
+       ss_sort_na(&ss_Version);
+       s0 = s = ss_Version.symbol;
+       if (debug)
+               fprintf(stderr, "DEBUG: Version %s\n",
+                       format_Version(s0->address));
+       for (i = 0; i < ss_Version.used; ++i, ++s) {
+               if (s->address != s0->address) {
+                       fprintf(stderr,
+                               "Version mismatch error.  %s says %s, ",
+                               s0->name,
+                               format_Version(s0->address));
+                       fprintf(stderr,
+                               "%s says %s.  Expect lots of address "
+                               "mismatches.\n",
+                               s->name,
+                               format_Version(s->address));
+                       ++errors;
+               }
+       }
+       prev_used = ss_Version.used;
+}
diff --git a/scripts/ksymoops.cc b/scripts/ksymoops.cc
deleted file mode 100644 (file)
index 13fb451..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-// ksymoops.cc v1.7 -- A simple filter to resolve symbols in Linux Oops-logs
-// Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
-// compile like so: g++ -o ksymoops ksymoops.cc -liostream
-
-// Update to binutils 2.8 and handling of header text on oops lines by
-// Keith Owens <kaos@ocs.com.au>
-
-//////////////////////////////////////////////////////////////////////////////
-
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2, or (at your option)
-// any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program; see the file COPYING.  If not, write to the
-// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-// This is a simple filter to resolve EIP and call-trace symbols from
-// a Linux kernel "Oops" log.  Supply the symbol-map file name as a
-// command-line argument, and redirect the oops-log into stdin.  Out
-// will come the EIP and call-trace in symbolic form.
-
-// Changed by Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-// adapted to Linux/m68k
-
-//////////////////////////////////////////////////////////////////////////////
-
-// BUGS:
-// * Only resolves operands of jump and call instructions.
-
-#include <fstream.h>
-#include <strstream.h>
-#include <iomanip.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <a.out.h>
-
-inline int strnequ(char const* x, char const* y, size_t n) { return (strncmp(x, y, n) == 0); }
-
-const int code_size = 20;
-
-//////////////////////////////////////////////////////////////////////////////
-
-class KSym
-{
-    friend class NameList;
-
-  private:
-    unsigned long address_;
-    char* name_;
-    long offset_;
-    long extent_;
-
-  private:
-    istream& scan(istream&);
-    ostream& print(ostream&) const;
-    void set_extent(KSym const& next_ksym) { extent_ = next_ksym.address_ - address_; }
-
-  public:
-    friend istream& operator >> (istream& is, KSym& k) { return k.scan(is); }
-    friend ostream& operator << (ostream& os, const KSym& k) { return k.print(os); }
-};
-
-istream&
-KSym::scan(istream& is)
-{
-    is >> ::hex >> address_;
-    char type;
-    is >> type;
-    char name[128];
-    is >> name;
-    name_ = new char [strlen(name)+1];
-    strcpy(name_, name);
-    offset_ = 0;
-    return is;
-}
-
-ostream&
-KSym::print(ostream& os) const
-{
-    os << ::hex << address_ + offset_ << ' ' << '<' << name_;
-    if (offset_)
-       os << '+' << ::hex << offset_ << '/' << ::hex << extent_;
-    return os << '>';
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-class NameList
-{
-  private:
-    // Caution: Fixed Allocation!
-    // This should suffice for awhile since 1.1.86 has only 2482 symbols.
-    KSym ksyms_0_[8000];
-    int cardinality_;
-
-  public:
-    NameList() : cardinality_(0) { }
-    
-  private:
-    istream& scan(istream&);
-
-  public:
-    int valid() { return (cardinality_ > 0); }
-       
-    KSym* find(unsigned long address);
-    void decode(unsigned char* code, long eip_addr);
-    
-  public:
-    friend istream& operator >> (istream& is, NameList& n) { return n.scan(is); }
-};
-
-KSym*
-NameList::find(unsigned long address)
-{
-    if (!valid())
-       return 0;
-    KSym* start = ksyms_0_;
-    KSym* end = &ksyms_0_[cardinality_ - 1];
-    if (address < start->address_ || address >= end->address_)
-       return 0;
-
-    KSym* mid;
-    while (start <= end) {
-       mid = &start[(end - start) / 2];
-       if (mid->address_ < address)
-           start = mid + 1;
-       else if (mid->address_ > address)
-           end = mid - 1;
-       else
-           return mid;
-    }
-    while (mid->address_ > address)
-       --mid;
-    mid->offset_ = address - mid->address_;
-    if (mid->offset_ > mid->extent_)
-       clog << "Oops! " << *mid << endl;
-    return mid;
-}
-
-void
-NameList::decode(unsigned char* code, long eip_addr)
-{
-    /* This is a hack to avoid using gcc.  We create an object file by
-       concatenating objfile_head, the twenty bytes of code, and
-       objfile_tail.  */
-    static struct exec objfile_head = {
-       OMAGIC, code_size + 4, 0, 0, sizeof (struct nlist) * 3, 0, 0, 0
-    };
-    static struct {
-       unsigned char tail[4];
-       struct nlist syms[3];
-       unsigned long strsize;
-       char strings[42];
-    } objfile_tail = {
-#ifdef i386
-       { 0x00, 0x90, 0x90, 0x90 },
-#endif
-#ifdef mc68000
-       { 0x00, 0x00, 0x00, 0x00 },
-#endif
-       { { (char *) 4, N_TEXT, 0, 0, 0 },
-         { (char *) 19, N_TEXT, 0, 0, 0 },
-         { (char *) 37, N_TEXT | N_EXT, 0, 0, 0 } },
-       42,
-       "gcc2_compiled.\0___gnu_compiled_c\0_EIP\0"
-    };
-    char const* objdump_command = "objdump -d oops_decode.o";
-    char const* objfile_name = &objdump_command[11];
-    ofstream objfile_stream(objfile_name);
-
-    objfile_stream.write((char *) &objfile_head, sizeof(objfile_head));
-    objfile_stream.write(code, code_size);
-    objfile_stream.write((char *) &objfile_tail, sizeof(objfile_tail));
-    objfile_stream.close();
-    
-    FILE* objdump_FILE = popen(objdump_command, "r");
-    if (objdump_FILE == 0) {
-       clog << "Sorry, without " << objdump_command << ", I can't disassemble the `Code' section." << endl;
-       return;
-    }
-    
-    char buf[1024];
-    int lines = 0;
-    int eip_seen = 0;
-    long offset;
-    while (fgets(buf, sizeof(buf), objdump_FILE)) {
-       if (strlen(buf) < 14)
-           continue;
-       if (eip_seen && buf[4] == ':') {
-           // assume objdump from binutils 2.8..., reformat to old style
-           offset = strtol(buf, 0, 16);
-           char newbuf[sizeof(buf)];
-           memset(newbuf, '\0', sizeof(newbuf));
-           ostrstream ost(newbuf, sizeof(newbuf));
-           ost.width(8);
-           ost << hex << offset;
-           ost << " <_EIP+" << hex << offset << ">: " << &buf[6] << ends;
-           strcpy(buf, newbuf);
-       }
-       if (!strnequ(&buf[9], "<_EIP", 5))
-           continue;
-       eip_seen = 1;
-       if (strstr(buf, " is out of bounds"))
-           break;
-       lines++;
-       cout << "Code: ";
-       if (!valid()) {
-           cout << buf;
-           continue;
-       }
-       offset = strtol(buf, 0, 16);
-       char* bp_0 = strchr(buf, '>');
-       KSym* ksym = find(eip_addr + offset);
-       if (bp_0)
-           bp_0 += 2;
-       else
-           bp_0 = strchr(buf, ':');
-       if (ksym)
-           cout << *ksym << ' ';
-       char *bp_1 = strstr(bp_0, "\t");        // objdump from binutils 2.8...
-       if (bp_1)
-           ++bp_1;
-       else
-           bp_1 = bp_0;
-       char *bp = bp_1;
-       while (!isspace(*bp))
-           bp++;
-       while (isspace(*bp))
-           bp++;
-       if (!isxdigit(*bp)) {
-           cout << bp_0;
-#ifdef i386
-       } else if (*bp_1 == 'j' || strnequ(bp_1, "call", 4)) { // a jump or call insn
-           long rel_addr = strtol(bp, 0, 16);
-           ksym = find(eip_addr + rel_addr);
-           if (ksym) {
-               *bp++ = '\0';
-               cout << bp_0 << *ksym << endl;
-           } else
-               cout << bp_0;
-#endif
-#ifdef mc68000
-       } else if ((bp_1[0] == 'b' && bp_1[4] == ' ' && strchr("swl", bp_1[3]))
-                  || (bp_1[0] == 'd' && bp_1[1] == 'b')) {
-           // a branch or decr-and-branch insn
-           if (bp_1[0] == 'd') // skip register
-               while (*bp && *bp++ != ',');
-           long rel_addr = strtoul(bp, 0, 16);
-           ksym = find(eip_addr + rel_addr);
-           if (ksym) {
-               *bp++ = '\0';
-               cout << bp_0 << *ksym << endl;
-           } else
-             cout << bp_0;
-#endif
-       } else {
-           cout << bp_0;
-       }
-    }
-    if (!lines)
-       clog << "Sorry, your " << objdump_command << " can't disassemble--you must upgrade your binutils." << endl;
-    pclose(objdump_FILE);
-    unlink(objfile_name);
-}
-
-istream&
-NameList::scan(istream& is)
-{
-    KSym* ksyms = ksyms_0_;
-    int cardinality = 0;
-    while (!is.eof()) {
-       is >> *ksyms;
-       if (cardinality++ > 0)
-           ksyms[-1].set_extent(*ksyms);
-       ksyms++;
-    }
-    cardinality_ = --cardinality;
-    return is;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-char const* program_name;
-
-void
-usage()
-{
-    clog << "Usage: " << program_name << " [ System.map ] < oops-log" << endl;
-    exit(1);
-}
-
-int
-main(int argc, char** argv)
-{
-    char c;
-    char *oops_column = NULL;
-    program_name = (argc--, *argv++);
-
-    NameList names;
-    if (argc > 1)
-       usage();
-    else if (argc == 1) {
-       char const* map_file_name = (argc--, *argv++);
-       ifstream map(map_file_name);
-       if (map.bad())
-           clog << program_name << ": Can't open `" << map_file_name << "'" << endl;
-       else {
-           map >> names;
-           cout << "Using `" << map_file_name << "' to map addresses to symbols." << endl;
-       }
-    }
-    if (!names.valid())
-       cout << "No symbol map.  I'll only show you disassembled code." << endl;
-    cout << endl;
-
-    char buffer[1024];
-    while (1) {
-       long eip_addr;
-       cin.get(buffer, sizeof(buffer));
-       if (cin.eof())
-           break;
-       cin.get(c);     /* swallow newline */
-#ifdef i386
-       if (strstr(buffer, "EIP:") && names.valid()) {
-           oops_column =  strstr(buffer, "EIP:");
-           if (sscanf(oops_column+13, "[<%x>]", &eip_addr) != 1) {
-               cout << "Cannot read eip address from EIP: line.  Is this a valid oops file?" << endl;
-               exit(1);
-           }
-           cout << ">>EIP: ";
-           KSym* ksym = names.find(eip_addr);
-           if (ksym)
-               cout << *ksym << endl;
-           else
-               cout << ::hex << eip_addr << " cannot be resolved" << endl;
-       }
-#endif
-#ifdef mc68000
-       if (strstr(buffer, "PC:") && names.valid()) {
-           oops_column =  strstr(buffer, "PC:");
-           if (sscanf(oops_column+4, "[<%x>]", &eip_addr) != 1) {
-               cout << "Cannot read pc address from PC: line.  Is this a valid oops file?" << endl;
-               exit(1);
-           }
-           cout << ">>PC: ";
-           KSym* ksym = names.find(eip_addr);
-           if (ksym)
-               cout << *ksym << endl;
-           else
-               cout << ::hex << eip_addr << " cannot be resolved" << endl;
-       }
-#endif
-       else if (oops_column && strstr(oops_column, "[<") && names.valid()) {
-           unsigned long address;
-           while (strstr(oops_column, "[<")) {
-               char *p = oops_column;
-               while (1) {
-                   while (*p && *p++ != '[')
-                       ;
-                   if (sscanf(p, "<%x>]", &address) != 1)
-                       break;
-                   cout << "Trace: ";
-                   KSym* ksym = names.find(address);
-                   if (ksym)
-                       cout << *ksym;
-                   else
-                       cout << ::hex << address;
-                   cout << endl;
-               }
-               cin.get(buffer, sizeof(buffer));
-               if (cin.eof())
-                   break;
-               cin.get(c);     /* swallow newline */
-           }
-       }
-       if (oops_column && strnequ(oops_column, "Code:", 5)) {
-           unsigned char code[code_size];
-           unsigned char* cp = code;
-           unsigned char* end = &code[code_size];
-           char *p = oops_column + 5;
-           int c;
-           memset(code, '\0', sizeof(code));
-           while (*p && cp < end) {
-               while (*p == ' ')
-                   ++p;
-               if (sscanf(p, "%x", &c) != 1)
-                   break;
-#ifdef mc68000
-               *cp++ = c >> 8;
-#endif
-               *cp++ = c;
-               while (*p && *p++ != ' ')
-                   ;
-           }
-           names.decode(code, eip_addr);
-       }
-    }
-    cout << flush;
-
-    return 0;
-}
index fc133295d978079943d2c0555658970f5c924208..d63b95c0a51ed682541c98f380f699d78a1cadb9 100644 (file)
@@ -132,8 +132,8 @@ void fix_choice_cond(void)
            }
          else
            {
-             fprintf(stderr,"Ooops\n");
-             exit(0);
+             fprintf(stderr,"tkparse can't handle this conditional\n");
+             exit(1);
            }
        }