diff options
Diffstat (limited to 'exec')
-rw-r--r-- | exec/ChangeLog | 843 | ||||
-rw-r--r-- | exec/Makefile | 40 | ||||
-rw-r--r-- | exec/core.c | 264 | ||||
-rw-r--r-- | exec/crypt.h | 12 | ||||
-rw-r--r-- | exec/do-bunzip2.c | 1745 | ||||
-rw-r--r-- | exec/elfcore.c | 100 | ||||
-rw-r--r-- | exec/exec.c | 2065 | ||||
-rw-r--r-- | exec/execmutations.h | 6 | ||||
-rw-r--r-- | exec/exectrans.c | 79 | ||||
-rw-r--r-- | exec/gcore.c | 88 | ||||
-rw-r--r-- | exec/gzip.h | 315 | ||||
-rw-r--r-- | exec/hashexec.c | 429 | ||||
-rw-r--r-- | exec/hostarch.c | 187 | ||||
-rw-r--r-- | exec/inflate.c | 954 | ||||
-rw-r--r-- | exec/main.c | 259 | ||||
-rw-r--r-- | exec/priv.h | 153 | ||||
-rw-r--r-- | exec/tailor.h | 14 | ||||
-rw-r--r-- | exec/unzip.c | 199 | ||||
-rw-r--r-- | exec/util.c | 272 |
19 files changed, 8024 insertions, 0 deletions
diff --git a/exec/ChangeLog b/exec/ChangeLog new file mode 100644 index 00000000..dd1e37b4 --- /dev/null +++ b/exec/ChangeLog @@ -0,0 +1,843 @@ +1999-11-08 Roland McGrath <roland@baalperazim.frob.com> + + * exectrans.c (trivfs_support_write, trivfs_support_exec): Variables + removed. + (trivfs_allow_open): Set to just O_READ. + +1999-09-09 Roland McGrath <roland@baalperazim.frob.com> + + * Makefile (exec.static-LDFLAGS): Variable removed. + +1999-07-17 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (servercopy): Removed unused variable. + +1999-07-11 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (load_section): Fix typos in last change. + +1999-07-11 Thomas Bushnell, BSG <tb@mit.edu> + + * exec.c (load_section): Use mmap instead of vm_allocate when + allocating in mach_task_self (). + (servercopy): Likewise. + (do_exec): Likewise. + * hashexec.c (check_hashbang): Likewise. + +1999-07-10 Roland McGrath <roland@baalperazim.frob.com> + + * hostarch.c (mach_host_elf_machine): Replaced with ... + (elf_machine_matches_host): New function. Instead of returning + an ELF EM_* code, take one and check if it matches the host; + operate only on mach_host_self(), cache results, + Grok CPU_TYPE_{I486,PENTIUM,PENTIUMPRO} to accept EM_386 or EM_486. + Grok POWERPC, ALPHA, HPPA types. + * exec.c (check_elf): Call elf_machine_matches_host instead of + comparing against elf_machine. + (load_section): #if 0 out no-op code that uses elf_machine. + * priv.h (elf_machine_matches_host): Declare it. + (elf_machine, mach_host_elf_machine): Remove decls. + * main.c (main) [!BFD]: Don't call mach_host_elf_machine. + (elf_machine): Variable removed. + + * exec.c (map): Don't cast arg to munmap to vm_address_t. + + * priv.h: Add #include <sys/mman.h> for munmap decl. + +1999-07-03 Thomas Bushnell, BSG <tb@mit.edu> + + * core.c (core_dump_task): Use munmap instead of vm_deallocate, + when it's from our own task. + * elfcore.c: Likewise. + * exec.c (load_section): Likewise. + (map): Likewise. + (close_exec_stream): Likewise. + (finish_mapping): Likewise. + (load): Likewise. + (do_exec): Likewise. + (S_exec_setexecdata): Likewise. + * hashexec.c (check_hashbang): Likewise. + * main.c (deadboot): Likewise. + +1999-06-04 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (map): Fix mapping calls to use F->__offset consistently + instead of F->__target. + +1999-05-16 Roland McGrath <roland@baalperazim.frob.com> + + * hashexec.c (check_hashbang): Fix bug in last change. + +1999-05-15 Roland McGrath <roland@baalperazim.frob.com> + + * hashexec.c (check_hashbang): Trim trailing blanks after interpreter + argument. + +1998-09-05 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp> + + * do-bunzip2.c: New file. + * exec.c (check_bzip2): New function. + (BZIP2): New cpp symbol. If defined, bunzip2 engine is enabled. + * Makefile (bzip2-objects): New variable. + (OBJS): Add bzip2-objects. + (CPPFLAGS): Add -DBZIP2. + +1999-04-27 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (do_exec): Implement EXEC_SIGTRAP flag. + +1998-12-27 Roland McGrath <roland@baalperazim.frob.com> + + * main.c (S_exec_init): Deallocate PROCSERVER port when finished. + +1998-12-27 Roland McGrath <roland@baalperazim.frob.com> + + * main.c (S_exec_init): Remove variable DEV_MASTER; pass null instead + since we don't need it. Use assert_perror on getting the host-priv + port and on startup_essential_task, since init will hang until we've + done made that RPC. + +1998-12-26 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (do_exec): Fix conditional for cleaning up INTERP, + from nonnull E.interp.section to nonnull INTERP.file. + If we failed to open the interpreter file, INTERP.file will be + null and the rest of INTERP will be uninitialized. + +1998-12-21 Roland McGrath <roland@baalperazim.frob.com> + + * main.c (S_exec_init): Don't call set_active_trans. + (set_active_trans): Function removed. + + * Makefile (HURDLIBS): Add missing implied library deps. + +1998-11-25 Mark Kettenis <kettenis@phys.uva.nl> + + * main.c (S_exec_init): Call _hurd_proc_init with new args set to + zero. + + * hashexec.c (check_hashbang): Fix typo: interplen -> interp_len. + +Thu Nov 5 15:26:50 1998 Thomas Bushnell, BSG <tb@mit.edu> + + * hashexec.c (check_hashbang): Keep INTERP_LEN with the correct + value (bytes of memory holding INTERP) for later use. + (check_hashbang: setup_args): Set argv[0] from the interpreter + name, not copied from the existing command line. + +1998-10-26 Roland McGrath <roland@baalperazim.frob.com> + + * hashexec.c: Use mach_* instead of __mach_*. + +1998-07-15 Roland McGrath <roland@baalperazim.frob.com> + + * exec.c (do_exec): Set boot->phdr_addr and boot->user_entry after + loading, to addresses adjusted for actual run-time load address. + +Wed Aug 20 14:02:11 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * main.c (main): New args for + ports_manage_port_operations_multithread. + +1997-06-30 Miles Bader <miles@gnu.ai.mit.edu> + + * main.c (main): Arg parsing added. + (argp_program_version): New variable. + Include <argp.h>. + +Mon Jan 20 16:16:33 1997 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): `preempter' -> `preemptor'. + +Sat Nov 23 16:26:55 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * priv.h (mach_host_elf_machine): New prototype. + * hostarch.c: Include "priv.h". + +Mon Nov 18 17:45:48 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * exec.c (load_section): If ANYWHERE, then make sure ADDR starts + out at least past the first page, so that we don't take it. Then + the library can (if desired) make the page no-access. + +Fri Nov 15 17:34:23 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * exec.c: Don't include <hurd/shared.h> any more. + + * main.c (S_exec_init): New arg syntax of trivfs_open. + +Mon Oct 7 21:31:25 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * exec.c (fake_seek): New function. + (prepare): Initialize E->stream.__io_funcs.seek to fake_seek; this + is called now that stdio doesn't assume it always knows the file + position. + +Thu Sep 12 16:30:12 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * Makefile (HURDLIBS): New variable. + (exec): Delete special dependencies. + +Thu Sep 5 11:11:19 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * main.c: Include <version.h>. + (exec_version): Delete variable. + (S_exec_init): Pass empty string as release; HURD_VERSION + as version. + +Thu Aug 29 13:00:38 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * priv.h: Only include <bfd.h> if BFD. Only declare + host_bfd_arc_info, and bfd_host_bfd if BFD. If not BFD, give + typedef for asection. + * main.c: Only define host_bfd_arch_info, host_bfd, and + bfd_mach_host_arch_mach if BFD. + (main): Only call bfd_mach_most_arch_mach if BFD. + Call mach_host_elf_machine. + * hostarch.c (bfd_mach_host_arch_mach): Only define if BFD. + Delete arg E_MACHINE. All callers changed. + (mach_host_elf_machine): New function. + +Sun Jul 7 21:13:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * exec.c (S_exec_exec): Don't use unsafe MOVE_SEND in call to + interruptible exec_exec stub. + +Mon Jul 1 16:08:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * Makefile (DIST_FILES): Removed crash.c. + * crash.c: Moved to ../trans. + +Thu Jun 20 15:43:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * Makefile (exec): Link against fshelp too now. + + * exec.c (do_exec): Call proc_setowner *after* possible + proc_reassign; otherwise it modifies the stub process's state and + not the real process's. + +Wed Jun 19 14:08:15 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * exec.c (do_exec, S_exec_exec): Pass 0 for new LOOKUP arg to + hurd_file_name_lookup. + * hashexec.c (hurd_file_name_path_lookup): Declaration removed. + (check_hashbang): Pass 0 for new LOOKUP arg to hurd_file_name_lookup. + +Wed Jun 12 21:17:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * gzip.h (basename): Comment out declaration; it conflicts with + libc's. + + * exec.c (do_exec): If secure, set the owner with proc_setowner. + +Fri May 10 16:47:11 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (search_path): Don't make PATH or PFXED_NAME const. + +Fri May 10 09:20:26 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * exec.c (do_exec) [use1]: Use new auth_user_authenticate interface. + * hashexec.c (check_hashbang) [userport/reauthenticate]: Likewise. + + * hashexec.c (check_hashbang) [setup_args/search_path]: Declare + PATH to be `char const *'. + +Tue May 7 16:24:52 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): Use io_identity instead of io_stat to + compare files. + +Mon May 6 14:26:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * main.c (exec_version): Upgrade to 0.0. + +Fri May 3 14:16:17 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> + + * exec.c (map): Use F->__offset and F->__target properly. + +Thu May 2 10:21:37 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> + + * exec.c (map): Fix fencepost error in check of current mapping + window. Request round_page (LEN) bytes in io_read to avoid many small + reads. + + * exec.c (do_exec): Terminate OLDTASK if we get an error after killing + its threads and deallocating its address space. + +Tue Apr 30 11:36:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * exec.c (check_gzip) [ziprderr]: Treat all read errors as + ENOEXEC. First off, because that's what they are; also because + some callers of read_error don't set errno at all. + +Mon Apr 29 15:11:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * exec.c (check_section): If the format makes no sense, return + ENOEXEC, not EINVAL. + (check_bfd): Likewise. + (check_elf): Likewise. + (check_elf_phdr): Likewise. + (do_exec): Likewise. + + * exec.c (do_exec): Use correct args to ports_create_port. + +Sat Apr 27 06:02:42 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> + + * crash.c: Use ports_create_port instead of ports_allocate_port, and + notice the error. + * exec.c: Likewise. + +Tue Apr 23 18:53:54 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> + + * hashexec.c (check_hashbang: user_port): Use default root port when + secure. + +Mon Apr 15 12:48:35 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * Makefile (DIST_FILES): Add elfcore.c, crash.c, and exectrans.c. + (SRCS): That's hashexec.c, not .o. + + * Makefile (exec-MIGSFLAGS): Look for execmutations.h in + $(srcdir). + +Mon Apr 8 15:49:39 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * exec.c (prepare): If io_map returns EOPNOTSUPP, suppress the + error, and still setup E's stream. + (prepare_and_check): If prepare returns an error, do no more. + +Thu Mar 28 14:06:07 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): Pass open flags & mode args to + hurd_file_name_path_lookup. + +Mon Feb 26 16:33:22 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): Correctly deal with interpreter + lines having no argument. + +Sat Jan 13 12:28:03 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): Use hash_file_name_path_lookup() + instead of doing the path search ourselves, and get rid of + LOOKUP_CWDIR & associated logic. + * exec.c (S_exec_exec): Use strdupa(). Also update use of + hurd_file_name_lookup() [still probably not right though]. + +Thu Jan 11 15:36:18 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * hashexec.c (check_hashbang): When using executable name found on + the path, don't return alloca()ed memory from search_path(); use + malloc() instead. + Use envz_get() to search the environment. + + * exec.c (S_exec_exec): Use envz_get() to search the environment. + +Thu Jan 4 11:30:15 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (safe_bzero): Rewritten using hurd_catch_signal. + * hashexec.c (check_hashbang): Rearrange arg frobbing code + somewhat to use hurd_catch_signal instead of old preemption interface. + +Fri Dec 29 15:54:06 1995 Miles Bader <miles@gnu.ai.mit.edu> + + * exec.c (do_exec): Be careful not to look at BOOT after we + release our reference on it. + Correctly initialize BOOT->intarray in the case where NINTS < + INIT_INT_MAX but we don't alloc a new array. + +Fri Dec 15 01:53:07 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (map): Rearrange code to fix some bugs and not remap + unless necessary. + (input_room): Simplify. + (check_elf): Extract all information from file header before + calling `map' for program headers. + +Sat Nov 25 22:10:41 1995 Miles Bader <miles@gnu.ai.mit.edu> + + * crash.c (S_msg_sig_post_untraced): Also let the debugger have + the process back if it's posting the crashing signal. + +Tue Nov 21 15:01:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (safe_bzero): New function, broken out of load_section. + (load_section): Call it. + + * main.c (going_down): Variable removed. + (deadboot): Don't test it. Instead, use ports calls to check if + there are no other live ports. + (trivfs_goaway): Don't set it. + +Wed Nov 15 19:40:44 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * hashexec.c (user_port): Fixed port selection logic. + (check_hashbang): Fixed PATH searching in script name guessing. + +Mon Nov 13 15:11:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (S_exec_startup): Compatibility RPC removed. + + * exec.c (load_section): Catch faults while zeroing partial bss page. + +Sun Nov 5 00:15:07 1995 Miles Bader <miles@gnu.ai.mit.edu> + + * main.c (main): Add flags arg to trivfs_startup call. + +Wed Oct 25 15:50:38 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (S_exec_startup_get_info): New function, modified from + S_exec_startup. + (S_exec_startup): Just call it. + * main.c (exec_demuxer): Call exec_startup_server. + +Tue Oct 24 19:21:20 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (OBJS): Add exec_startupServer.o. + + * priv.h (struct bootinfo): Use vm_size_t for phdr_size. + +Wed Oct 18 18:36:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * hashexec.c (check_hashbang: prepare_args): Enable and clean up + code to guess the name of the script before resorting to /dev/fd. + +Wed Oct 18 03:05:05 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * hashexec.c: New file. + * exec.c (struct execdata): Moved to priv.h. + (std_*, finish): Make global. + (do_exec): Only reset CWDIR when null, even if secure. + Actually call check_hashbang and return success if it does. + Use new hurd_file_name_lookup protocol with private callbacks to open + interpreter file on behalf of client. + Remove `bootout' label; use `stdout' or `out' as appropriate instead. + At `out' label always deref BOOT, which cleans it up iff necessary. + (S_exec_exec): #if 0 out $EXECSERVERS processing for time being. + * priv.h: Added some #includes. + (struct execdata): Moved here from exec.c. + (std_*): Declare these. + (finish, check_hashbang): Declare them. + * Makefile (SRCS, OBJS): Add hashexec.[co]. + (DIST_FILES): Remove it from here. + +Wed Oct 11 01:45:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * main.c, priv.h, execmutations.h: New files. + * exec.c: Server mechanics removed; now uses libtrivfs/libports. + Main program split out into main.c. + (std_lock): New variable (rwlock). + (do_exec): Acquire reader lock to access std_ints and std_ports. + (S_exec_setexecdata): Acquire writer lock to change them. + * Makefile (OBJS): Add main.o; remove fsysServer.o, notifyServer.o. + (LCLHDRS): Add priv.h and execmutations.h. + (exec-MIGSFLAGS): New variable. + (exec): Depend on livtrivfs, libthreads, libshouldbeinlibc. + +Mon Oct 2 10:33:14 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * exec.c (do_exec): Doc fix. + +Wed Sep 27 11:21:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (do_exec): Don't set NEWTASK's bootstrap port until after + we have finished completely with OLDTASK. + (do_mach_notify_no_senders): Remove bogus mod_refs call on + receive_portset. + +Wed Sep 20 19:57:55 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (struct bootinfo): New members `phdr_addr', `phdr_size', + `user_entry'. + (do_exec): Set them. Code rearranged to construct bootinfo before + looking up interpreter file, keep proper track of port rights and + VM copied into bootinfo (there were leaks). + +Sat Sep 16 13:15:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile: Remove vpath directive. + +Fri Sep 8 17:50:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (OTHERLIBS, CPPFLAGS): Disable bfd by default. + +Mon Aug 28 16:57:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (S_fsys_forward): New stub function. + +Sun Jul 30 23:49:49 1995 Michael I. Bushnell, p/BSG <mib@geech.gnu.ai.mit.edu> + * Makefile (SRCS): Added unzip.c, util.c, and inflate.c. + +Thu Jul 6 15:32:39 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * hostarch.c (bfd_mach_host_arch_mach): Remove assignment from + inside if test. + + * Makefile: Removed dependencies that are now automatically + generated. + +Wed Jul 5 18:00:49 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * Makefile (OTHERLIBS): Define var. + (all, exec): Delete targets. + +Tue Jun 27 11:48:08 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * exec.c (load_section): Remove assignments from if tests. + (map): Likewise. + (prepare): Likewise. + (load): Likewise. + (servercopy): Likewise. + (do_exec): Likewise. + (S_exec_setexecdata): Likewise. + (S_exec_exec): Put extra parens around assignment inside while + test. + +Thu Jun 8 02:57:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (struct execdata.info.elf): Add members `anywhere' and + `loadbase'. + (load_section): Use them; if `anywhere' set, load the section anywhere. + Record load address in `loadbase'. + (check_elf): Initialize `anywhere' and `loadbase'. + (postload): Merged into load. + (load): Perform postload functionality here, after calling + finish_mapping. + (finish): Take new flag arg; deallocate file port only if set. + (do_exec): Pass flag to finish appropriately. + Don't call finish_mapping and postload after load. KLUDGE: Load + the interpreter before the program instead of after. + +Mon Jun 5 06:42:33 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c: Majorly revamped: Now supports the ELF format directly. + Secondarily uses the BFD library #ifdef BFD. Supports gunzipping + only #ifdef GZIP. + * hostarch.c: Rewritten to unconditionally return both BFD and ELF + machine types. + +Fri May 12 18:59:21 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> + + * exec.c (S_fsys_set_options, S_fsys_mod_readonly): Change from + mod_readonly to set_options. + +Thu Apr 20 22:14:47 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (check_gzip): Rewind the stream before calling + `get_method'. Open a new BFD on the uncompressed data stream + before return. + +Sun Apr 9 01:27:10 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (struct execdata) [BFD]: New member `interp_section'. + (check_section): Notice section named ".interp" and set that pointer. + (load_section): Do nothing if the section is zero size. + When reading into our copy of the overlap page, don't read past + the end of the section. + (do_exec): Consolidate new subfunction `check_maybe_gzip'. + If there is an interpreter section, load the interpreter file too, + and use its entry point instead of the user program's. Cleaned up + and made more robust deallocation of BOOT info on error. + (deadboot): New function, split out of do_mach_port_notify_no_senders. + + * Makefile (vpath lib%.a): Add search path. + (exec): Depend on -lbfd and -liberty. + (CPPFLAGS): Append -DBFD; omit -DA_OUT_H=... + (bfdexec): Target removed. + * exec.c (load_section): fseek to desired position before freading. + (input_room): Always map a page-aligned region. + +Thu Feb 9 01:01:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (check_section): Don't check SEC_RELOC flag. + +Wed Feb 8 19:48:11 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * exec.c (load_section) [BFD]: BFD does not set SEC_HAS_CONTENTS + on a.out BSS's ever; don't make zeroing of bss conditional on that. + It's not clear exactly what SEC_HAS_CONTENTS is for anyhow; + perhaps the Right Thing is to set in on BSS. In any case, don't + depend on this flag here. + +Sat Jan 28 17:08:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (prepare): Give the stream a seek function. + +Sun Jan 22 03:16:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c: Update BFD code; it works now. + * hostarch.c [BFD]: Fix prototype. + +Thu Jan 19 01:24:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * hostarch.c: Add case for CPU_TYPE_ALPHA. + + * hostarch.c (bfd_mach_host_arch_mach, aout_mach_host_machine): + Use mach_msg_type_number_t instead of unsigned int. Cast + &HOSTINFO to (natural_t *). + +Sun Jan 15 06:29:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c [BFD] (bfd_mach_host_arch_mach): In decl, MACHINE arg is + `long int *' now. + [BFD] (host_bfd_arch_info): New variable. + [BFD] (host_bfd): Initialize `arch_info' member to its address. + (check) [BFD]: Use bfd_arch_get_compatible properly, rather than the + nonexistent bfd_arch_compatible. + (main) [BFD]: Fill in host_bfd.arch_info instead of old + `obj_machine' and `obj_archiecture' members, which BFD no longer has. + * hostarch.c [BFD] (bfd_mach_host_arch_mach): MACHINE arg is `long + int *' now. + +Tue Dec 13 23:28:08 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (OBJS): Add unzip.o util.o inflate.o. + (LCLHDRS): Add gzip.h crypt.h tailor.h. + (unzip.o util.o inflate.o): Depend on those. + (CFLAGS): Use +=. + * inflate.c, unzip.c, util.c, tailor.h, gzip.h, crypt.h: New files. + +Sun Dec 11 19:49:01 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (struct execdata): New members `headbuf', `file_data', + `optimal_block'. + (load_section): Copy data from U->file_data if that is nonnull. + Use new subfunction `write_to_task' that handles non-page aligned + sections. + (input_room): Fix EOF check. + Use io_read if no memory object. + (prepare): New function, broken out of check. + Initialize E->file_data and E->optimal_block. Set + E->stream.__seen bit. + (check): No longer take FILE arg. + Use E->file_data if nonnull; else read from stream if no memory object. + (finish_mapping): Reset members after deallocating resources. + (finish): Likewise. Call fclose. Don't deallocate E->header if + it points to &E->headbuf or E->file_data. + (check_gzip): New function, implements executing gzip'd binaries. + (do_exec): Call prepare before check. + Call check_gzip if file format unrecognized. + +Wed Nov 9 01:40:28 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (set_active_trans): Don't deallocate EXECNODE here to + work around a ufs bug. + + * exec.c: Include <hurd/paths.h> and <fcntl.h>. + (set_active_trans): New function. + (S_exec_init): Call set_active_trans. + +Wed Aug 31 11:16:04 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (load_section): Pass address of stream in call to fread. + (input_room): Cast second arg to vm_deallocate. Dereference F + in setting __error member. + (close_exec_stream): Provide all three args to vm_deallocate + and cast the second one properly. + +Wed Aug 31 04:32:26 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c (do_exec): Do check before task_suspend. + #if 0'd out: If check gets ENOEXEC, call check_hashbang. + (struct execdata): Move member `stream' outside of [BFD]. + (load_section): Use fread instead of hand mapping and copying + unconditionally (was [BFD]); old code left #if'd out. + (close_exec_stream): Renamed from close_stdio_bfd; moved out of [BFD]. + (input_room): Define unconditionally, not [BFD]. + (check): Set up E->stream unconditionally. + +Tue Aug 30 11:58:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (S_fsys_syncfs, S_fsys_mod_readonly): New stubs. + + * exec.c (set_init_port): Use new authentication protocol. + + * exec.c (S_exec_exec): Call hurd_file_name_lookup instead + of hurd_path_lookup. + + * exec.c (S_fsys_getroot): Return FS_RETRY_NORMAL instead + of FS_RETRY_NONE. + + * exec.c (procserver): New global variable. + (S_exec_init): Set procserver. + (do_exec): Use `procserver' instead of USEPORT macro. + (S_exec_init): Likewise. + +Mon Aug 29 13:08:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (do_exec): Enable and fix up code for doing proc_reassign + in the EXEC_NEWTASK case. + (do_exec): If we don't provide the proc port, and this is a + newtask exec, then use the proc port to fetch a new one + corresponding to the new task. + +Wed Aug 17 14:59:58 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (S_exec_exec): Bother to pass flags to do_exec. + + * exec.c (essentialstartupport, essentialhostport): Deleted vars. + (S_exec_init): Do startup_essential_task here like before, but + make sure we do it last. + (S_exec_setexecdata): Don't do startup_essential_task here. + +Tue Aug 16 10:02:50 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (set_init_port): Don't assume that MACH_PORT_NULL == 0. + (do_exec): Likewise. + +Mon Aug 15 21:23:13 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * exec.c: Include <unistd.h> for getpid decl. + (set_init_port): Use pid_t for PID. + (S_exec_init): Pass poly arg to proc_execdata_notify. + +Mon Aug 15 15:24:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * exec.c (do_exec): Finish implementing EXEC_SECURE flag; + implement EXEC_DEFAULTS flag. + (S_exec_init): Delay startup_essential_task until after + we've received the first essential ports from the proc server. + (essentialstartupport essentialhostport): New global vars. + +Fri Jul 22 10:21:30 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * Makefile: Rewritten in accord with new scheme. + * exec.c: Include "exec_S.h" instead of "exec_server.h". + Include "notify_S.h". + +Tue Jul 19 20:51:58 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Makefile (exec_server.h execServer.c, fsys_S.h fsysServer.c): + Find .defs file in ../hurd, not $(includedir). + +Tue Jul 19 12:42:32 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * exec.c (S_fsys_getroot): New arg `dotdot'; don't do anything + with it. + (S_fsys_startup): Removed dotdot args. + (main): Deleted var `dotdot'; don't expect it from fsys_startup. + + * Makefile (exec): Don't use variable $(link) anymore. + +Tue Jul 5 14:20:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * Makefile (SRCS, TAGSHDRS): New variables. + +Fri Jun 24 14:42:59 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * exec.c (load_section) [AOUT, mapstart > addr]: Dereference + U->header in use of N_MAGIC. + +Fri Jun 24 02:40:32 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (load_section): Store protection of section in new local + VM_PROT. If vm_write of overlap page gets KERN_PROTECTION_FAILURE, + change protection of overlap page long enough to write it. + [AOUT]: Return ENOEXEC if there is overlap in NMAGIC or ZMAGIC. + +Thu Jun 16 16:15:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * exec.c (S_fsys_getroot): Implement new fsys_getroot interface. + +Mon Jun 13 04:06:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * exec.c (check): Store FILE in E->file. + +Tue May 31 17:20:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * a.out.h (struct exec): Type removed. + (OMAGIC, NMAGIC, ZMAGIC, N_MAGIC, N_MACHTYPE, N_BADMAG): Macros + removed. Just #include "a.out.gnu.h" to get all these defined. + (N_TXTLEN, N_TXTOFF): Use N_MAGIC instead of a_magic member. + + * Makefile (DIST_FILES): Add a.out.gnu.h. + (exec.o, hostarch.o): Depend on a.out.gnu.h. + +Fri May 27 01:40:04 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (servercopy): New function to check the servercopy flag + and possibly vm_allocate a copy of argument data. + (do_exec): Take new args DTABLE_COPY, PORTARRAY_COPY, + INTARRAY_COPY. Use servercopy for ARGV, ENVP, DTABLE, PORTARRAY, + and INTARRAY. + (S_exec_exec): Take those new args and pass them to do_exec. + (S_exec_setexecdata): Take new args PORTS_COPY and INTS_COPY. + Use servercopy for PORTS and INTS. + (S_exec_startup): Never copy from info in *BOOT, always just set + the argument pointers to the pointers in *BOOT. MiG will copy and + deallocate the space as necessary. + + * exec.c (check): Lock and unlock E->cntl->lock properly. + (finish_mapping): New function, broken out of finish. + (postload_section): New function, broken out of load_section. + (postload): New function, like load but calls postload_section. + (do_exec): Call finish_mapping and postload between load and finish. + +Tue May 24 19:49:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (S_exec_exec): Use strsep instead of strtok. + (main): Keep looping after error from mach_msg_server. + +Tue May 24 14:22:16 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * exec.c (load_section): Cast arg to vm_deallocate properly. + +Tue May 24 01:05:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (struct bootinfo): Remove members argv_vmalloc, envp_vmalloc. + (do_exec): Don't set BOOT->argv_vmalloc or BOOT->envp_vmalloc. If + ARGV_COPY is set, vm_allocate space for ARGV; likewise for + ENVP_COPY and ENVP. + (S_exec_startup): Don't test BOOT->argv_vmalloc and + BOOT->envp_vmalloc; BOOT->argv and BOOT->envp are always vm_allocate'd. + (do_mach_notify_no_senders): Likewise. + (load_section): Handle non-bss sections that are not page aligned. + +Mon May 23 22:01:11 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (S_exec_exec): Reverse args to memmem. + (do_exec): Don't vm_deallocate DEALLOCNAMES or DESTROYNAMES; mig + deallocates the space for us. + +Tue May 17 13:33:41 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * exec.c (S_exec_init): Don't deallocate host_priv until after + we've used it in the call to startup_essential_task. + +Thu May 12 03:53:57 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (S_fsys_init): Add reply port args. + +Wed May 11 16:03:07 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * exec.c (S_exec_init): Spelling fix. + + * Makefile (exec.o): Add dependencies on fsys_S.h and notify_S.h. + (fsysServer.c, notifyServer.c): Notice that these rules build + fsys_S.h and notify_S.h respectively. + +Mon May 9 17:06:52 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * exec.c (exec_version, save_argv): New variable. + (main): Set save_argv. + (S_exec_init): Give the real argv to proc. + Call proc_register_version if we can. + (S_exec_init): Call startup_essential_task if we can. + +Thu May 5 06:25:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Makefile: Change uses of $(headers) to $(includedir). + + * exec.c: Change return type of all RPC server functions to + kern_return_t. error_t is not compatible with the declarations in + the mig-generated header files. + + * exec.c (do_exec): Set BOOT->stack_base and BOOT->stack_size with + mach_setup_thread. + (S_exec_exec): Pass msg type arg for FILE arg to exec_exec. + +Thu Dec 23 18:05:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * exec.c (do_exec): For a newtask exec when EXEC_SECURE is not set + and OLDTASK is not null, send the `task_create' RPC on OLDTASK + rather than mach_task_self (). diff --git a/exec/Makefile b/exec/Makefile new file mode 100644 index 00000000..5f9666b7 --- /dev/null +++ b/exec/Makefile @@ -0,0 +1,40 @@ +# Copyright (C) 1993, 94, 95, 96, 98, 99 Free Software Foundation, Inc. +# This file is part of the GNU Hurd. +# +# The GNU Hurd 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. +# +# The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +dir := exec +makemode := server + +SRCS = exec.c main.c hashexec.c hostarch.c unzip.c util.c inflate.c +OBJS = main.o hostarch.o exec.o hashexec.o \ + execServer.o exec_startupServer.o \ + $(gzip-objects) $(bzip2-objects) +gzip-objects = unzip.o util.o inflate.o +bzip2-objects = do-bunzip2.o +LCLHDRS = gzip.h crypt.h tailor.h priv.h execmutations.h +target = exec +#targets = exec exec.static +DIST_FILES = core.c gcore.c elfcore.c exectrans.c +#OTHERLIBS = -lbfd -liberty +HURDLIBS=trivfs fshelp iohelp ports ihash threads shouldbeinlibc + +exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h + +include ../Makeconf + +CPPFLAGS += -DGZIP -DBZIP2 # -DBFD + +exec.static exec: $(OBJS) $(library_deps) diff --git a/exec/core.c b/exec/core.c new file mode 100644 index 00000000..f79b6b08 --- /dev/null +++ b/exec/core.c @@ -0,0 +1,264 @@ +/* GNU Hurd standard core server. + Copyright (C) 1992, 1999 Free Software Foundation, Inc. + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include "core_server.h" +#include <bfd.h> +#include <string.h> + +/* Uses nonexistent bfd function: */ +char *bfd_intuit_section_name (bfd_vma vma, bfd_size_type size, + flagword *flags); + +/* Object file format to write core files in. */ +static char *core_target = NULL; + +/* Dump a core from TASK into FILE. + SIGNO and SIGCODE indicate the signal that killed the process. */ + +error_t +core_dump_task (mach_port_t coreserver, + task_t task, + file_t file, + int signo, int sigcode, + const char *my_target) +{ + error_t err; + + processor_set_name_t pset; + host_t host; + processor_set_basic_info_data_t pinfo; + + thread_t *threads; + size_t nthreads; + + vm_address_t addr; + vm_size_t size; + vm_prot_t prot, maxprot; + vm_inherit_t inherit; + boolean_t shared; + memory_object_name_t objname; + vm_offset_t offset; + + bfd *bfd; + bfd_architecture arch; + bfd_machine machine; + asection *sec; + + /* The task is suspended while we examine it. + In the case of a post-mortem dump, the only thread not suspended will + be the signal thread, which will be blocked waiting for this RPC to + return. But for gcore, threads might be running. And Leviticus + specifies that only suspended threads be thread_info'd, anyway. */ + if (err = task_suspend (task)) + goto lose; + + /* Figure out what flavor of machine the task is on. */ + if (err = task_get_assignment (task, &pset)) + goto lose; + err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host, + &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT); + mach_port_deallocate (mach_task_self (), pset); + if (err) + goto lose; + err = bfd_mach_host_arch_mach (host, &arch, &machine); + mach_port_deallocate (mach_task_self (), host); + if (err) + goto lose; + + /* Open the BFD. */ + bfd = NULL; + { + FILE *f = fopenport (file, "w"); + if (f == NULL) + { + err = errno; + goto lose; + } + bfd = bfd_openstream (f, my_target ?: core_target); + if (bfd == NULL) + { + err = errno; + (void) fclose (f); + errno = err; + goto bfdlose; + } + } + + bfd_set_arch_mach (bfd, arch, machine); + + /* XXX How are thread states stored in bfd? */ + if (err = task_threads (task, &threads, &nthreads)) + goto lose; + + /* Create a BFD section to describe each contiguous chunk + of the task's address space with the same stats. */ + sec = NULL; + addr = 0; + while (!vm_region (task, &addr, &size, &prot, &maxprot, + &inherit, &shared, &objname, &offset)) + { + mach_port_deallocate (mach_task_self (), objname); + + if (prot != VM_PROT_NONE) + { + flagword flags = SEC_NO_FLAGS; + + if (!(prot & VM_PROT_WRITE)) + flags |= SEC_READONLY; + if (!(prot & VM_PROT_EXECUTE)) + flags |= SEC_DATA; + + if (sec != NULL && + (vm_address_t) (bfd_section_vma (bfd, sec) + + bfd_section_size (bfd, sec)) == addr && + flags == (bfd_get_section_flags (bfd, sec) & + (SEC_READONLY|SEC_DATA))) + /* Coalesce with the previous section. */ + bfd_set_section_size (bfd, sec, + bfd_section_size (bfd, sec) + size); + else + { + /* Make a new section (which might grow by + the next region being coalesced onto it). */ + char *name = bfd_intuit_section_name (addr, size, &flags); + if (name == NULL) + { + /* No guess from BFD. */ + if (asprintf (&name, "[%p,%p) %c%c%c", + (void *) addr, (void *) (addr + size), + (prot & VM_PROT_READ) ? 'r' : '-', + (prot & VM_PROT_WRITE) ? 'w' : '-', + (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1) + goto lose; + } + sec = bfd_make_section (name); + bfd_set_section_flags (bfd, sec, flags); + bfd_set_section_vma (bfd, sec, addr); + bfd_set_section_size (bfd, sec, size); + } + } + } + + /* Write all the sections' data. */ + for (sec = bfd->sections; sec != NULL; sec = sec->next) + { + void *data; + err = vm_read (task, bfd_section_vma (bfd, sec), + bfd_section_size (bfd, sec), &data); + if (err) + /* XXX What to do? + 1. lose + 2. remove this section + 3. mark this section as having ungettable contents (how?) + */ + goto lose; + err = bfd_set_section_contents (bfd, sec, data, 0, + bfd_section_size (bfd, sec)); + munmap ((caddr_t) data, bfd_section_size (bfd, sec)); + if (err) + goto bfdlose; + } + + bfdlose: + switch (bfd_error) + { + case system_call_error: + err = errno; + break; + + case no_memory: + err = ENOMEM; + break; + + default: + err = EGRATUITOUS; + break; + } + + lose: + if (bfd != NULL) + bfd_close (bfd); + else + mach_port_deallocate (mach_task_self (), file); + task_resume (task); + mach_port_deallocate (mach_task_self (), task); + return err; +} + +error_t +fsys_getroot (fsys_t fsys, idblock_t id, file_t realnode, file_t dotdot, + file_t *root) +{ + *root = core; + mach_port_deallocate (mach_task_self (), realnode); + mach_port_deallocate (mach_task_self (), dotdot); + return POSIX_SUCCESS; +} + +mach_port_t request_portset; + +int +request_server (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + if (inp->msgh_local_port == fsys) + return fsys_server (inp, outp); + else if (inp->msgh_local_port == core) + return (core_server (inp, outp) || + io_server (inp, outp) || + fs_server (inp, outp)); +} + +int +main (int argc, char **argv) +{ + error_t err; + fsys_t fsys; + mach_port_t boot, dotdot; + + if ((err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &fsys)) || + (err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &core))) + hurd_perror ("mach_port_allocate", err); + else if (err = task_get_bootstrap_port (mach_task_self (), &boot)) + hurd_perror ("task_get_bootstrap_port", err); + else if (err = fsys_startup (boot, fsys, &realnode, &dotdot)) + hurd_perror ("fsys_startup", err); + mach_port_deallocate (mach_task_self (), dotdot); + + mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_PORT_SET, &request_portset); + + mach_port_move_member (mach_task_self (), fsys, request_portset); + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &core); + mach_port_move_member (mach_task_self (), core, request_portset); + + mach_port_mod_refs (mach_task_self (), realnode, MACH_PORT_RIGHT_SEND, 1); + + core_target = argv[1]; + + do + err = mach_msg_server (request_server, vm_page_size, request_portset); + while (!err); + hurd_perror ("mach_msg_server", err); + return 1; +} diff --git a/exec/crypt.h b/exec/crypt.h new file mode 100644 index 00000000..2a4c203c --- /dev/null +++ b/exec/crypt.h @@ -0,0 +1,12 @@ +/* crypt.h (dummy version) -- do not perform encryption + * Hardly worth copyrighting :-) + */ + +#ifdef CRYPT +# undef CRYPT /* dummy version */ +#endif + +#define RAND_HEAD_LEN 12 /* length of encryption random header */ + +#define zencode +#define zdecode diff --git a/exec/do-bunzip2.c b/exec/do-bunzip2.c new file mode 100644 index 00000000..17bbf911 --- /dev/null +++ b/exec/do-bunzip2.c @@ -0,0 +1,1745 @@ +/* bunzip2 engine, modified by okuji@kuicr.kyoto-u.ac.jp. */ + +/* Stolen from util.c. */ +#include <stdio.h> +#include <sys/types.h> + +/* I/O interface */ +extern int (*unzip_read) (char *buf, size_t maxread); +extern void (*unzip_write) (const char *buf, size_t nwrite); +extern void (*unzip_read_error) (void); +extern void (*unzip_error) (const char *msg); + +/* bzip2 doesn't require window sliding. Just for buffering. */ +#define INBUFSIZ 0x1000 +#define OUTBUFSIZ 0x1000 + +static unsigned char inbuf[INBUFSIZ]; +static unsigned char outbuf[OUTBUFSIZ]; +static unsigned inptr; +static unsigned insize; +static unsigned outcnt; + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty. + */ +static int +fill_inbuf (int eof_ok) +{ + int len; + + /* Read as much as possible */ + insize = 0; + do + { + len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize); + if (len == 0 || len == EOF) + break; + insize += len; + } + while (insize < INBUFSIZ); + + if (insize == 0) + { + if (eof_ok) + return EOF; + unzip_read_error(); + } + + inptr = 1; + return inbuf[0]; +} + +static void +flush_outbuf (void) +{ + if (outcnt == 0) + return; + + (*unzip_write) ((char *) outbuf, outcnt); + outcnt = 0; +} + +static inline int +bz2_getc (void *stream) +{ + return inptr < insize ? inbuf[inptr++] : fill_inbuf (1); +} + +static inline int +bz2_putc (int c, void *stream) +{ + if (outcnt == OUTBUFSIZ) + flush_outbuf (); + outbuf[outcnt++] = c; + return c; +} + +static inline int +bz2_ferror (void *stream) +{ + return 0; +} + +static inline int +bz2_fflush (void *stream) +{ + flush_outbuf (); + return 0; +} + +static inline int +bz2_fclose (void *stream) +{ + flush_outbuf (); + return 0; +} + +#define fprintf(s, f...) /**/ + + +/*-----------------------------------------------------------*/ +/*--- A block-sorting, lossless compressor bzip2.c ---*/ +/*-----------------------------------------------------------*/ + +/*-- + This program is bzip2, a lossless, block-sorting data compressor, + version 0.1pl2, dated 29-Aug-1997. + + Copyright (C) 1996, 1997 by Julian Seward. + Guildford, Surrey, UK + email: jseward@acm.org + + 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 of the License, 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; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The GNU General Public License is contained in the file LICENSE. + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the file ALGORITHMS. +--*/ + +/*----------------------------------------------------*/ +/*--- IMPORTANT ---*/ +/*----------------------------------------------------*/ + +/*-- + WARNING: + This program (attempts to) compress data by performing several + non-trivial transformations on it. Unless you are 100% familiar + with *all* the algorithms contained herein, and with the + consequences of modifying them, you should NOT meddle with the + compression or decompression machinery. Incorrect changes can + and very likely *will* lead to disasterous loss of data. + + DISCLAIMER: + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the + complexity of the algorithms, and, in particular, the presence + of various special cases in the code which occur with very low + but non-zero probability make it impossible to rule out the + possibility of bugs remaining in the program. DO NOT COMPRESS + ANY DATA WITH THIS PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE + POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2 has been + carefully constructed and extensively tested. + + PATENTS: + To the best of my knowledge, bzip2 does not use any patented + algorithms. However, I do not have the resources available to + carry out a full patent search. Therefore I cannot give any + guarantee of the above statement. +--*/ + + + +/*----------------------------------------------------*/ +/*--- and now for something much more pleasant :-) ---*/ +/*----------------------------------------------------*/ + +/*---------------------------------------------*/ +/*-- + Place a 1 beside your platform, and 0 elsewhere. +--*/ + +/*-- + Generic 32-bit Unix. + Also works on 64-bit Unix boxes. +--*/ +#define BZ_UNIX 1 + +/*-- + Win32, as seen by Jacob Navia's excellent + port of (Chris Fraser & David Hanson)'s excellent + lcc compiler. +--*/ +#define BZ_LCCWIN32 0 + + + +/*---------------------------------------------*/ +/*-- + Some stuff for all platforms. +--*/ + +#include <stdio.h> +#include <stdlib.h> +#if DEBUG + #include <assert.h> +#endif +#include <string.h> +#include <signal.h> +#include <math.h> + +#define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); } +#define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); } +#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); } + + +/*---------------------------------------------*/ +/*-- + Platform-specific stuff. +--*/ + +#if BZ_UNIX + #include <sys/types.h> + #include <utime.h> + #include <unistd.h> + #include <malloc.h> + #include <sys/stat.h> + #include <sys/times.h> + + #define Int32 int + #define UInt32 unsigned int + #define Char char + #define UChar unsigned char + #define Int16 short + #define UInt16 unsigned short + + #define PATH_SEP '/' + #define MY_LSTAT lstat + #define MY_S_IFREG S_ISREG + #define MY_STAT stat + + #define APPEND_FILESPEC(root, name) \ + root=snocString((root), (name)) + + #define SET_BINARY_MODE(fd) /**/ + + /*-- + You should try very hard to persuade your C compiler + to inline the bits marked INLINE. Otherwise bzip2 will + run rather slowly. gcc version 2.x is recommended. + --*/ + #ifdef __GNUC__ + #define INLINE inline + #define NORETURN __attribute__ ((noreturn)) + #else + #define INLINE /**/ + #define NORETURN /**/ + #endif +#endif + + + +#if BZ_LCCWIN32 + #include <io.h> + #include <fcntl.h> + #include <sys\stat.h> + + #define Int32 int + #define UInt32 unsigned int + #define Int16 short + #define UInt16 unsigned short + #define Char char + #define UChar unsigned char + + #define INLINE /**/ + #define NORETURN /**/ + #define PATH_SEP '\\' + #define MY_LSTAT _stat + #define MY_STAT _stat + #define MY_S_IFREG(x) ((x) & _S_IFREG) + + #if 0 + /*-- lcc-win32 seems to expand wildcards itself --*/ + #define APPEND_FILESPEC(root, spec) \ + do { \ + if ((spec)[0] == '-') { \ + root = snocString((root), (spec)); \ + } else { \ + struct _finddata_t c_file; \ + long hFile; \ + hFile = _findfirst((spec), &c_file); \ + if ( hFile == -1L ) { \ + root = snocString ((root), (spec)); \ + } else { \ + int anInt = 0; \ + while ( anInt == 0 ) { \ + root = snocString((root), \ + &c_file.name[0]); \ + anInt = _findnext(hFile, &c_file); \ + } \ + } \ + } \ + } while ( 0 ) + #else + #define APPEND_FILESPEC(root, name) \ + root = snocString ((root), (name)) + #endif + + #define SET_BINARY_MODE(fd) \ + do { \ + int retVal = setmode ( fileno ( fd ), \ + O_BINARY ); \ + ERROR_IF_MINUS_ONE ( retVal ); \ + } while ( 0 ) + +#endif + + +/*---------------------------------------------*/ +/*-- + Some more stuff for all platforms :-) +--*/ + +#define Bool unsigned char +#define True 1 +#define False 0 + +/*-- + IntNative is your platform's `native' int size. + Only here to avoid probs with 64-bit platforms. +--*/ +#define IntNative int + + +/*-- + change to 1, or compile with -DDEBUG=1 to debug +--*/ +#ifndef DEBUG +#define DEBUG 0 +#endif + + +/*---------------------------------------------------*/ +/*--- ---*/ +/*---------------------------------------------------*/ + +/*-- + Implementation notes, July 1997 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Memory allocation + ~~~~~~~~~~~~~~~~~ + All large data structures are allocated on the C heap, + for better or for worse. That includes the various + arrays of pointers, striped words, bytes, frequency + tables and buffers for compression and decompression. + + bzip2 can operate at various block-sizes, ranging from + 100k to 900k in 100k steps, and it allocates only as + much as it needs to. When compressing, we know from the + command-line options what the block-size is going to be, + so all allocation can be done at start-up; if that + succeeds, there can be no further allocation problems. + + Decompression is more complicated. Each compressed file + contains, in its header, a byte indicating the block + size used for compression. This means bzip2 potentially + needs to reallocate memory for each file it deals with, + which in turn opens the possibility for a memory allocation + failure part way through a run of files, by encountering + a file requiring a much larger block size than all the + ones preceding it. + + The policy is to simply give up if a memory allocation + failure occurs. During decompression, it would be + possible to move on to subsequent files in the hope that + some might ask for a smaller block size, but the + complications for doing this seem more trouble than they + are worth. + + + Compressed file formats + ~~~~~~~~~~~~~~~~~~~~~~~ + [This is now entirely different from both 0.21, and from + any previous Huffman-coded variant of bzip. + See the associated file bzip2.txt for details.] + + + Error conditions + ~~~~~~~~~~~~~~~~ + Dealing with error conditions is the least satisfactory + aspect of bzip2. The policy is to try and leave the + filesystem in a consistent state, then quit, even if it + means not processing some of the files mentioned in the + command line. `A consistent state' means that a file + exists either in its compressed or uncompressed form, + but not both. This boils down to the rule `delete the + output file if an error condition occurs, leaving the + input intact'. Input files are only deleted when we can + be pretty sure the output file has been written and + closed successfully. + + Errors are a dog because there's so many things to + deal with. The following can happen mid-file, and + require cleaning up. + + internal `panics' -- indicating a bug + corrupted or inconsistent compressed file + can't allocate enough memory to decompress this file + I/O error reading/writing/opening/closing + signal catches -- Control-C, SIGTERM, SIGHUP. + + Other conditions, primarily pertaining to file names, + can be checked in-between files, which makes dealing + with them easier. +--*/ + + + +/*---------------------------------------------------*/ +/*--- Misc (file handling) data decls ---*/ +/*---------------------------------------------------*/ + +static UInt32 bytesIn, bytesOut; +static Int32 verbosity; +static Bool smallMode; +static UInt32 globalCrc; + + + + +static void panic ( Char* ); +static void ioError ( void ); +static void uncompressOutOfMemory ( Int32, Int32 ); +static void blockOverrun ( void ); +static void badBlockHeader ( void ); +static void crcError ( UInt32, UInt32 ); +static void cleanUpAndFail ( Int32 ); +static void compressedStreamEOF ( void ); + + + +/*---------------------------------------------------*/ +/*--- Data decls for the front end ---*/ +/*---------------------------------------------------*/ + +/*-- + The overshoot bytes allow us to avoid most of + the cost of pointer renormalisation during + comparison of rotations in sorting. + The figure of 20 is derived as follows: + qSort3 allows an overshoot of up to 10. + It then calls simpleSort, which calls + fullGtU, also with max overshoot 10. + fullGtU does up to 10 comparisons without + renormalising, giving 10+10 == 20. +--*/ +#define NUM_OVERSHOOT_BYTES 20 + +/*-- + These are the main data structures for + the Burrows-Wheeler transform. +--*/ + +/*-- + Pointers to compression and decompression + structures. Set by + allocateCompressStructures and + setDecompressStructureSizes + + The structures are always set to be suitable + for a block of size 100000 * blockSize100k. +--*/ +static UInt16 *ll16; /*-- small decompress --*/ +static UChar *ll4; /*-- small decompress --*/ + +static Int32 *tt; /*-- fast decompress --*/ +static UChar *ll8; /*-- fast decompress --*/ + + +/*-- + freq table collected to save a pass over the data + during decompression. +--*/ +static Int32 unzftab[256]; + + +/*-- + index of the last char in the block, so + the block size == last + 1. +--*/ +static Int32 last; + + +/*-- + index in zptr[] of original string after sorting. +--*/ +static Int32 origPtr; + + +/*-- + always: in the range 0 .. 9. + The current block size is 100000 * this number. +--*/ +static Int32 blockSize100k; + + +/*-- + Used when sorting. If too many long comparisons + happen, we stop sorting, randomise the block + slightly, and try again. +--*/ + +static Bool blockRandomised; + + + +/*---------------------------------------------------*/ +/*--- Data decls for the back end ---*/ +/*---------------------------------------------------*/ + +#define MAX_ALPHA_SIZE 258 +#define MAX_CODE_LEN 23 + +#define RUNA 0 +#define RUNB 1 + +#define N_GROUPS 6 +#define G_SIZE 50 +#define N_ITERS 4 + +#define MAX_SELECTORS (2 + (900000 / G_SIZE)) + +static Bool inUse[256]; +static Int32 nInUse; + +static UChar seqToUnseq[256]; +static UChar unseqToSeq[256]; + +static UChar selector [MAX_SELECTORS]; +static UChar selectorMtf[MAX_SELECTORS]; + +static UChar len [N_GROUPS][MAX_ALPHA_SIZE]; + +/*-- decompress only --*/ +static Int32 limit [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 base [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 perm [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 minLens[N_GROUPS]; + + +/*---------------------------------------------------*/ +/*--- 32-bit CRC grunge ---*/ +/*---------------------------------------------------*/ + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +static UInt32 crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000UL, 0x04c11db7UL, 0x09823b6eUL, 0x0d4326d9UL, + 0x130476dcUL, 0x17c56b6bUL, 0x1a864db2UL, 0x1e475005UL, + 0x2608edb8UL, 0x22c9f00fUL, 0x2f8ad6d6UL, 0x2b4bcb61UL, + 0x350c9b64UL, 0x31cd86d3UL, 0x3c8ea00aUL, 0x384fbdbdUL, + 0x4c11db70UL, 0x48d0c6c7UL, 0x4593e01eUL, 0x4152fda9UL, + 0x5f15adacUL, 0x5bd4b01bUL, 0x569796c2UL, 0x52568b75UL, + 0x6a1936c8UL, 0x6ed82b7fUL, 0x639b0da6UL, 0x675a1011UL, + 0x791d4014UL, 0x7ddc5da3UL, 0x709f7b7aUL, 0x745e66cdUL, + 0x9823b6e0UL, 0x9ce2ab57UL, 0x91a18d8eUL, 0x95609039UL, + 0x8b27c03cUL, 0x8fe6dd8bUL, 0x82a5fb52UL, 0x8664e6e5UL, + 0xbe2b5b58UL, 0xbaea46efUL, 0xb7a96036UL, 0xb3687d81UL, + 0xad2f2d84UL, 0xa9ee3033UL, 0xa4ad16eaUL, 0xa06c0b5dUL, + 0xd4326d90UL, 0xd0f37027UL, 0xddb056feUL, 0xd9714b49UL, + 0xc7361b4cUL, 0xc3f706fbUL, 0xceb42022UL, 0xca753d95UL, + 0xf23a8028UL, 0xf6fb9d9fUL, 0xfbb8bb46UL, 0xff79a6f1UL, + 0xe13ef6f4UL, 0xe5ffeb43UL, 0xe8bccd9aUL, 0xec7dd02dUL, + 0x34867077UL, 0x30476dc0UL, 0x3d044b19UL, 0x39c556aeUL, + 0x278206abUL, 0x23431b1cUL, 0x2e003dc5UL, 0x2ac12072UL, + 0x128e9dcfUL, 0x164f8078UL, 0x1b0ca6a1UL, 0x1fcdbb16UL, + 0x018aeb13UL, 0x054bf6a4UL, 0x0808d07dUL, 0x0cc9cdcaUL, + 0x7897ab07UL, 0x7c56b6b0UL, 0x71159069UL, 0x75d48ddeUL, + 0x6b93dddbUL, 0x6f52c06cUL, 0x6211e6b5UL, 0x66d0fb02UL, + 0x5e9f46bfUL, 0x5a5e5b08UL, 0x571d7dd1UL, 0x53dc6066UL, + 0x4d9b3063UL, 0x495a2dd4UL, 0x44190b0dUL, 0x40d816baUL, + 0xaca5c697UL, 0xa864db20UL, 0xa527fdf9UL, 0xa1e6e04eUL, + 0xbfa1b04bUL, 0xbb60adfcUL, 0xb6238b25UL, 0xb2e29692UL, + 0x8aad2b2fUL, 0x8e6c3698UL, 0x832f1041UL, 0x87ee0df6UL, + 0x99a95df3UL, 0x9d684044UL, 0x902b669dUL, 0x94ea7b2aUL, + 0xe0b41de7UL, 0xe4750050UL, 0xe9362689UL, 0xedf73b3eUL, + 0xf3b06b3bUL, 0xf771768cUL, 0xfa325055UL, 0xfef34de2UL, + 0xc6bcf05fUL, 0xc27dede8UL, 0xcf3ecb31UL, 0xcbffd686UL, + 0xd5b88683UL, 0xd1799b34UL, 0xdc3abdedUL, 0xd8fba05aUL, + 0x690ce0eeUL, 0x6dcdfd59UL, 0x608edb80UL, 0x644fc637UL, + 0x7a089632UL, 0x7ec98b85UL, 0x738aad5cUL, 0x774bb0ebUL, + 0x4f040d56UL, 0x4bc510e1UL, 0x46863638UL, 0x42472b8fUL, + 0x5c007b8aUL, 0x58c1663dUL, 0x558240e4UL, 0x51435d53UL, + 0x251d3b9eUL, 0x21dc2629UL, 0x2c9f00f0UL, 0x285e1d47UL, + 0x36194d42UL, 0x32d850f5UL, 0x3f9b762cUL, 0x3b5a6b9bUL, + 0x0315d626UL, 0x07d4cb91UL, 0x0a97ed48UL, 0x0e56f0ffUL, + 0x1011a0faUL, 0x14d0bd4dUL, 0x19939b94UL, 0x1d528623UL, + 0xf12f560eUL, 0xf5ee4bb9UL, 0xf8ad6d60UL, 0xfc6c70d7UL, + 0xe22b20d2UL, 0xe6ea3d65UL, 0xeba91bbcUL, 0xef68060bUL, + 0xd727bbb6UL, 0xd3e6a601UL, 0xdea580d8UL, 0xda649d6fUL, + 0xc423cd6aUL, 0xc0e2d0ddUL, 0xcda1f604UL, 0xc960ebb3UL, + 0xbd3e8d7eUL, 0xb9ff90c9UL, 0xb4bcb610UL, 0xb07daba7UL, + 0xae3afba2UL, 0xaafbe615UL, 0xa7b8c0ccUL, 0xa379dd7bUL, + 0x9b3660c6UL, 0x9ff77d71UL, 0x92b45ba8UL, 0x9675461fUL, + 0x8832161aUL, 0x8cf30badUL, 0x81b02d74UL, 0x857130c3UL, + 0x5d8a9099UL, 0x594b8d2eUL, 0x5408abf7UL, 0x50c9b640UL, + 0x4e8ee645UL, 0x4a4ffbf2UL, 0x470cdd2bUL, 0x43cdc09cUL, + 0x7b827d21UL, 0x7f436096UL, 0x7200464fUL, 0x76c15bf8UL, + 0x68860bfdUL, 0x6c47164aUL, 0x61043093UL, 0x65c52d24UL, + 0x119b4be9UL, 0x155a565eUL, 0x18197087UL, 0x1cd86d30UL, + 0x029f3d35UL, 0x065e2082UL, 0x0b1d065bUL, 0x0fdc1becUL, + 0x3793a651UL, 0x3352bbe6UL, 0x3e119d3fUL, 0x3ad08088UL, + 0x2497d08dUL, 0x2056cd3aUL, 0x2d15ebe3UL, 0x29d4f654UL, + 0xc5a92679UL, 0xc1683bceUL, 0xcc2b1d17UL, 0xc8ea00a0UL, + 0xd6ad50a5UL, 0xd26c4d12UL, 0xdf2f6bcbUL, 0xdbee767cUL, + 0xe3a1cbc1UL, 0xe760d676UL, 0xea23f0afUL, 0xeee2ed18UL, + 0xf0a5bd1dUL, 0xf464a0aaUL, 0xf9278673UL, 0xfde69bc4UL, + 0x89b8fd09UL, 0x8d79e0beUL, 0x803ac667UL, 0x84fbdbd0UL, + 0x9abc8bd5UL, 0x9e7d9662UL, 0x933eb0bbUL, 0x97ffad0cUL, + 0xafb010b1UL, 0xab710d06UL, 0xa6322bdfUL, 0xa2f33668UL, + 0xbcb4666dUL, 0xb8757bdaUL, 0xb5365d03UL, 0xb1f740b4UL +}; + + +/*---------------------------------------------*/ + +static void initialiseCRC ( void ) +{ + globalCrc = 0xffffffffUL; +} + + +/*---------------------------------------------*/ + +static UInt32 getFinalCRC ( void ) +{ + return ~globalCrc; +} + + +/*---------------------------------------------*/ + +static UInt32 getGlobalCRC ( void ) +{ + return globalCrc; +} + + +/*---------------------------------------------*/ + +static void setGlobalCRC ( UInt32 newCrc ) +{ + globalCrc = newCrc; +} + + +/*---------------------------------------------*/ + +#define UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + + +static UInt32 bsBuff; +static Int32 bsLive; +static void* bsStream; +static Bool bsWriting; + + +/*---------------------------------------------*/ + +static void bsSetStream ( void* f, Bool wr ) +{ + if (bsStream != NULL) panic ( "bsSetStream" ); + bsStream = f; + bsLive = 0; + bsBuff = 0; + bytesOut = 0; + bytesIn = 0; + bsWriting = wr; +} + + +/*---------------------------------------------*/ + +static void bsFinishedWithStream ( void ) +{ + if (bsWriting) + while (bsLive > 0) { + bz2_putc ( (UChar)(bsBuff >> 24), bsStream ); + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + bsStream = NULL; +} + + +/*---------------------------------------------*/ + +#define bsNEEDR(nz) \ +{ \ + while (bsLive < nz) { \ + Int32 zzi = bz2_getc ( bsStream ); \ + if (zzi == EOF) compressedStreamEOF(); \ + bsBuff = (bsBuff << 8) | (zzi & 0xffL); \ + bsLive += 8; \ + } \ +} + + +/*---------------------------------------------*/ + +#define bsR1(vz) \ +{ \ + bsNEEDR(1); \ + vz = (bsBuff >> (bsLive-1)) & 1; \ + bsLive--; \ +} + + +/*---------------------------------------------*/ + +static INLINE UInt32 bsR ( Int32 n ) +{ + UInt32 v; + bsNEEDR ( n ); + v = (bsBuff >> (bsLive-n)) & ((1 << n)-1); + bsLive -= n; + return v; +} + + +/*---------------------------------------------*/ + +static UChar bsGetUChar ( void ) +{ + return (UChar)bsR(8); +} + + + +/*---------------------------------------------*/ + +static Int32 bsGetUInt32 ( void ) +{ + UInt32 u; + u = 0; + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + return u; +} + + +/*---------------------------------------------*/ + +static UInt32 bsGetIntVS ( UInt32 numBits ) +{ + return (UInt32)bsR(numBits); +} + + + +/*---------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------*/ + +static void hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + + +/*---------------------------------------------------*/ +/*--- Undoing the reversible transformation ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + ll4[(i) >> 1] = (ll4[(i) >> 1] & 0xf0) | (n); else \ + ll4[(i) >> 1] = (ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + + +#define GET_LL4(i) \ + (((UInt32)(ll4[(i) >> 1])) >> (((i) << 2) & 0x4) & 0xF) + + +#define SET_LL(i,n) \ + { ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + + +#define GET_LL(i) \ + (((UInt32)ll16[i]) | (GET_LL4(i) << 16)) + + +/*---------------------------------------------*/ +/*-- + Manage memory for compression/decompression. + When compressing, a single block size applies to + all files processed, and that's set when the + program starts. But when decompressing, each file + processed could have been compressed with a + different block size, so we may have to free + and reallocate on a per-file basis. + + A call with argument of zero means + `free up everything.' And a value of zero for + blockSize100k means no memory is currently allocated. +--*/ + + +/*---------------------------------------------*/ + +static void setDecompressStructureSizes ( Int32 newSize100k ) +{ + if (! (0 <= newSize100k && newSize100k <= 9 && + 0 <= blockSize100k && blockSize100k <= 9)) + panic ( "setDecompressStructureSizes" ); + + if (newSize100k == blockSize100k) return; + + blockSize100k = newSize100k; + + if (ll16 != NULL) free ( ll16 ); + if (ll4 != NULL) free ( ll4 ); + if (ll8 != NULL) free ( ll8 ); + if (tt != NULL) free ( tt ); + + if (newSize100k == 0) return; + + if (smallMode) { + + Int32 n = 100000 * newSize100k; + ll16 = malloc ( n * sizeof(UInt16) ); + ll4 = malloc ( ((n+1) >> 1) * sizeof(UChar) ); + + if (ll4 == NULL || ll16 == NULL) { + Int32 totalDraw + = n * sizeof(Int16) + ((n+1) >> 1) * sizeof(UChar); + uncompressOutOfMemory ( totalDraw, n ); + } + + } else { + + Int32 n = 100000 * newSize100k; + ll8 = malloc ( n * sizeof(UChar) ); + tt = malloc ( n * sizeof(Int32) ); + + if (ll8 == NULL || tt == NULL) { + Int32 totalDraw + = n * sizeof(UChar) + n * sizeof(UInt32); + uncompressOutOfMemory ( totalDraw, n ); + } + + } +} + + + +/*---------------------------------------------------*/ +/*--- The new back end ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +static void makeMaps ( void ) +{ + Int32 i; + nInUse = 0; + for (i = 0; i < 256; i++) + if (inUse[i]) { + seqToUnseq[nInUse] = i; + unseqToSeq[i] = nInUse; + nInUse++; + } +} + + + +/*---------------------------------------------*/ + +static void recvDecodingTables ( void ) +{ + Int32 i, j, t, nGroups, nSelectors, alphaSize; + Int32 minLen, maxLen; + Bool inUse16[16]; + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) + if (bsR(1) == 1) + inUse16[i] = True; else + inUse16[i] = False; + + for (i = 0; i < 256; i++) inUse[i] = False; + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) + if (bsR(1) == 1) inUse[i * 16 + j] = True; + + makeMaps(); + alphaSize = nInUse+2; + + /*--- Now the selectors ---*/ + nGroups = bsR ( 3 ); + nSelectors = bsR ( 15 ); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (bsR(1) == 1) j++; + selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + Int32 curr = bsR ( 5 ); + for (i = 0; i < alphaSize; i++) { + while (bsR(1) == 1) { + if (bsR(1) == 0) curr++; else curr--; + } + len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (len[t][i] > maxLen) maxLen = len[t][i]; + if (len[t][i] < minLen) minLen = len[t][i]; + } + hbCreateDecodeTables ( + &limit[t][0], &base[t][0], &perm[t][0], &len[t][0], + minLen, maxLen, alphaSize + ); + minLens[t] = minLen; + } +} + + +/*---------------------------------------------*/ + +#define GET_MTF_VAL(lval) \ +{ \ + Int32 zt, zn, zvec, zj; \ + if (groupPos == 0) { \ + groupNo++; \ + groupPos = G_SIZE; \ + } \ + groupPos--; \ + zt = selector[groupNo]; \ + zn = minLens[zt]; \ + zvec = bsR ( zn ); \ + while (zvec > limit[zt][zn]) { \ + zn++; bsR1(zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + lval = perm[zt][zvec - base[zt][zn]]; \ +} + + +/*---------------------------------------------*/ + +static void getAndMoveToFrontDecode ( void ) +{ + UChar yy[256]; + Int32 i, j, nextSym, limitLast; + Int32 EOB, groupNo, groupPos; + + limitLast = 100000 * blockSize100k; + origPtr = bsGetIntVS ( 24 ); + + recvDecodingTables(); + EOB = nInUse+1; + groupNo = -1; + groupPos = 0; + + /*-- + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + --*/ + for (i = 0; i <= 255; i++) unzftab[i] = 0; + + for (i = 0; i <= 255; i++) yy[i] = (UChar) i; + + last = -1; + + GET_MTF_VAL(nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == RUNA || nextSym == RUNB) { + UChar ch; + Int32 s = -1; + Int32 N = 1; + do { + if (nextSym == RUNA) s = s + (0+1) * N; else + if (nextSym == RUNB) s = s + (1+1) * N; + N = N * 2; + GET_MTF_VAL(nextSym); + } + while (nextSym == RUNA || nextSym == RUNB); + + s++; + ch = seqToUnseq[yy[0]]; + unzftab[ch] += s; + + if (smallMode) + while (s > 0) { + last++; + ll16[last] = ch; + s--; + } + else + while (s > 0) { + last++; + ll8[last] = ch; + s--; + }; + + if (last >= limitLast) blockOverrun(); + continue; + + } else { + + UChar tmp; + last++; if (last >= limitLast) blockOverrun(); + + tmp = yy[nextSym-1]; + unzftab[seqToUnseq[tmp]]++; + if (smallMode) + ll16[last] = seqToUnseq[tmp]; else + ll8[last] = seqToUnseq[tmp]; + + /*-- + This loop is hammered during decompression, + hence the unrolling. + + for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; + --*/ + + j = nextSym-1; + for (; j > 3; j -= 4) { + yy[j] = yy[j-1]; + yy[j-1] = yy[j-2]; + yy[j-2] = yy[j-3]; + yy[j-3] = yy[j-4]; + } + for (; j > 0; j--) yy[j] = yy[j-1]; + + yy[0] = tmp; + GET_MTF_VAL(nextSym); + continue; + } + } +} + + +/*---------------------------------------------------*/ +/*--- Stuff for randomising repetitive blocks ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ +static Int32 rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +#define RAND_DECLS \ + Int32 rNToGo = 0; \ + Int32 rTPos = 0; \ + +#define RAND_MASK ((rNToGo == 1) ? 1 : 0) + +#define RAND_UPD_MASK \ + if (rNToGo == 0) { \ + rNToGo = rNums[rTPos]; \ + rTPos++; if (rTPos == 512) rTPos = 0; \ + } \ + rNToGo--; + + + +/*---------------------------------------------------*/ +/*--- The Reversible Transformation (tm) ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + + +static INLINE Int32 indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + + +#define GET_SMALL(cccc) \ + \ + cccc = indexIntoF ( tPos, cftab ); \ + tPos = GET_LL(tPos); + + + +static void undoReversibleTransformation_small ( void* dst ) +{ + Int32 cftab[257], cftabAlso[257]; + Int32 i, j, tmp, tPos; + UChar ch; + + /*-- + We assume here that the global array unzftab will + already be holding the frequency counts for + ll8[0 .. last]. + --*/ + + /*-- Set up cftab to facilitate generation of indexIntoF --*/ + cftab[0] = 0; + for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1]; + for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1]; + + /*-- Make a copy of it, used in generation of T --*/ + for (i = 0; i <= 256; i++) cftabAlso[i] = cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i <= last; i++) { + ch = (UChar)ll16[i]; + SET_LL(i, cftabAlso[ch]); + cftabAlso[ch]++; + } + + /*-- + Compute T^(-1) by pointer reversal on T. This is rather + subtle, in that, if the original block was two or more + (in general, N) concatenated copies of the same thing, + the T vector will consist of N cycles, each of length + blocksize / N, and decoding will involve traversing one + of these cycles N times. Which particular cycle doesn't + matter -- they are all equivalent. The tricky part is to + make sure that the pointer reversal creates a correct + reversed cycle for us to traverse. So, the code below + simply reverses whatever cycle origPtr happens to fall into, + without regard to the cycle length. That gives one reversed + cycle, which for normal blocks, is the entire block-size long. + For repeated blocks, it will be interspersed with the other + N-1 non-reversed cycles. Providing that the F-subscripting + phase which follows starts at origPtr, all then works ok. + --*/ + i = origPtr; + j = GET_LL(i); + do { + tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != origPtr); + + /*-- + We recreate the original by subscripting F through T^(-1). + The run-length-decoder below requires characters incrementally, + so tPos is set to a starting value, and is updated by + the GET_SMALL macro. + --*/ + tPos = origPtr; + + /*-------------------------------------------------*/ + /*-- + This is pretty much a verbatim copy of the + run-length decoder present in the distribution + bzip-0.21; it has to be here to avoid creating + block[] as an intermediary structure. As in 0.21, + this code derives from some sent to me by + Christian von Roques. + + It allows dst==NULL, so as to support the test (-t) + option without slowing down the fast decompression + code. + --*/ + { + IntNative retVal; + Int32 i2, count, chPrev, ch2; + UInt32 localCrc; + + count = 0; + i2 = 0; + ch2 = 256; /*-- not a char and not EOF --*/ + localCrc = getGlobalCRC(); + + { + RAND_DECLS; + while ( i2 <= last ) { + chPrev = ch2; + GET_SMALL(ch2); + if (blockRandomised) { + RAND_UPD_MASK; + ch2 ^= (UInt32)RAND_MASK; + } + i2++; + + if (dst) + retVal = bz2_putc ( ch2, dst ); + + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_SMALL(z); + if (blockRandomised) { + RAND_UPD_MASK; + z ^= RAND_MASK; + } + for (j2 = 0; j2 < (Int32)z; j2++) { + if (dst) retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + } + + setGlobalCRC ( localCrc ); + } + /*-- end of the in-line run-length-decoder. --*/ +} +#undef GET_SMALL + + +/*---------------------------------------------*/ + +#define GET_FAST(cccc) \ + \ + cccc = ll8[tPos]; \ + tPos = tt[tPos]; + + + +static void undoReversibleTransformation_fast ( void* dst ) +{ + Int32 cftab[257]; + Int32 i, tPos; + UChar ch; + + /*-- + We assume here that the global array unzftab will + already be holding the frequency counts for + ll8[0 .. last]. + --*/ + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + cftab[0] = 0; + for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1]; + for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1]; + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i <= last; i++) { + ch = (UChar)ll8[i]; + tt[cftab[ch]] = i; + cftab[ch]++; + } + + /*-- + We recreate the original by subscripting L through T^(-1). + The run-length-decoder below requires characters incrementally, + so tPos is set to a starting value, and is updated by + the GET_FAST macro. + --*/ + tPos = tt[origPtr]; + + /*-------------------------------------------------*/ + /*-- + This is pretty much a verbatim copy of the + run-length decoder present in the distribution + bzip-0.21; it has to be here to avoid creating + block[] as an intermediary structure. As in 0.21, + this code derives from some sent to me by + Christian von Roques. + --*/ + { + IntNative retVal; + Int32 i2, count, chPrev, ch2; + UInt32 localCrc; + + count = 0; + i2 = 0; + ch2 = 256; /*-- not a char and not EOF --*/ + localCrc = getGlobalCRC(); + + if (blockRandomised) { + RAND_DECLS; + while ( i2 <= last ) { + chPrev = ch2; + GET_FAST(ch2); + RAND_UPD_MASK; + ch2 ^= (UInt32)RAND_MASK; + i2++; + + retVal = bz2_putc ( ch2, dst ); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_FAST(z); + RAND_UPD_MASK; + z ^= RAND_MASK; + for (j2 = 0; j2 < (Int32)z; j2++) { + retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + + } else { + + while ( i2 <= last ) { + chPrev = ch2; + GET_FAST(ch2); + i2++; + + retVal = bz2_putc ( ch2, dst ); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_FAST(z); + for (j2 = 0; j2 < (Int32)z; j2++) { + retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + + } /*-- if (blockRandomised) --*/ + + setGlobalCRC ( localCrc ); + } + /*-- end of the in-line run-length-decoder. --*/ +} +#undef GET_FAST + + + +/*---------------------------------------------------*/ +/*--- Processing of complete files and streams ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +static Bool uncompressStream ( void *zStream, void *stream ) +{ + UChar magic1, magic2, magic3, magic4; + UChar magic5, magic6; + UInt32 storedBlockCRC, storedCombinedCRC; + UInt32 computedBlockCRC, computedCombinedCRC; + Int32 currBlockNo; + IntNative retVal; + + SET_BINARY_MODE(stream); + SET_BINARY_MODE(zStream); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + + bsSetStream ( zStream, False ); + + /*-- + A bad magic number is `recoverable from'; + return with False so the caller skips the file. + --*/ + magic1 = bsGetUChar (); + magic2 = bsGetUChar (); + magic3 = bsGetUChar (); + magic4 = bsGetUChar (); + if (magic1 != 'B' || + magic2 != 'Z' || + magic3 != 'h' || + magic4 < '1' || + magic4 > '9') { + bsFinishedWithStream(); + retVal = bz2_fclose ( stream ); + ERROR_IF_EOF ( retVal ); + return False; + } + + setDecompressStructureSizes ( magic4 - '0' ); + computedCombinedCRC = 0; + + if (verbosity >= 2) fprintf ( stderr, "\n " ); + currBlockNo = 0; + + while (True) { + magic1 = bsGetUChar (); + magic2 = bsGetUChar (); + magic3 = bsGetUChar (); + magic4 = bsGetUChar (); + magic5 = bsGetUChar (); + magic6 = bsGetUChar (); + if (magic1 == 0x17 && magic2 == 0x72 && + magic3 == 0x45 && magic4 == 0x38 && + magic5 == 0x50 && magic6 == 0x90) break; + + if (magic1 != 0x31 || magic2 != 0x41 || + magic3 != 0x59 || magic4 != 0x26 || + magic5 != 0x53 || magic6 != 0x59) badBlockHeader(); + + storedBlockCRC = bsGetUInt32 (); + + if (bsR(1) == 1) + blockRandomised = True; else + blockRandomised = False; + + currBlockNo++; + if (verbosity >= 2) + fprintf ( stderr, "[%d: huff+mtf ", currBlockNo ); + getAndMoveToFrontDecode (); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + + initialiseCRC(); + if (verbosity >= 2) fprintf ( stderr, "rt+rld" ); + if (smallMode) + undoReversibleTransformation_small ( stream ); + else + undoReversibleTransformation_fast ( stream ); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + + computedBlockCRC = getFinalCRC(); + if (verbosity >= 3) + fprintf ( stderr, " {0x%x, 0x%x}", storedBlockCRC, computedBlockCRC ); + if (verbosity >= 2) fprintf ( stderr, "] " ); + + /*-- A bad CRC is considered a fatal error. --*/ + if (storedBlockCRC != computedBlockCRC) + crcError ( storedBlockCRC, computedBlockCRC ); + + computedCombinedCRC = (computedCombinedCRC << 1) | (computedCombinedCRC >> 31); + computedCombinedCRC ^= computedBlockCRC; + }; + + if (verbosity >= 2) fprintf ( stderr, "\n " ); + + storedCombinedCRC = bsGetUInt32 (); + if (verbosity >= 2) + fprintf ( stderr, + "combined CRCs: stored = 0x%x, computed = 0x%x\n ", + storedCombinedCRC, computedCombinedCRC ); + if (storedCombinedCRC != computedCombinedCRC) + crcError ( storedCombinedCRC, computedCombinedCRC ); + + + bsFinishedWithStream (); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + retVal = bz2_fclose ( zStream ); + ERROR_IF_EOF ( retVal ); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + retVal = bz2_fflush ( stream ); + ERROR_IF_NOT_ZERO ( retVal ); + return True; +} + + +#if 0 + +#endif +/*---------------------------------------------------*/ +/*--- Error [non-] handling grunge ---*/ +/*---------------------------------------------------*/ + + + +static void +myFree (void **p) +{ + free (*p); + *p = NULL; +} + +/*---------------------------------------------*/ +/* Ugg... Orignal code doesn't free dynamic allocated memories. */ + +static void cleanUpAndFail ( Int32 ec ) +{ + myFree ((void **) &ll16); + myFree ((void **) &ll4); + myFree ((void **) &ll8); + myFree ((void **) &tt); + + (*unzip_error) (NULL); +} + + +/*---------------------------------------------*/ + +static void panic ( Char* s ) +{ + cleanUpAndFail( 3 ); +} + + + +/*---------------------------------------------*/ + +static void crcError ( UInt32 crcStored, UInt32 crcComputed ) +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void compressedStreamEOF ( void ) +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void ioError ( ) +{ + cleanUpAndFail( 1 ); +} + + +/*---------------------------------------------*/ + +static void blockOverrun () +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void badBlockHeader () +{ + cleanUpAndFail( 2 ); +} + + + +/*---------------------------------------------*/ +static void uncompressOutOfMemory ( Int32 draw, Int32 blockSize ) +{ + cleanUpAndFail(1); +} + + + +/*-----------------------------------------------------------*/ +/*--- end bzip2.c ---*/ +/*-----------------------------------------------------------*/ + +void +do_bunzip2 (void) +{ + Bool ret; + + /*-- Initialise --*/ + ll4 = NULL; + ll16 = NULL; + ll8 = NULL; + tt = NULL; +#ifdef SMALL_BZIP2 + smallMode = True; +#else + smallMode = False; +#endif + verbosity = 0; + blockSize100k = 0; + bsStream = NULL; + + outcnt = 0; + inptr = 0; + insize = 0; + + ret = uncompressStream ((void *)1, (void *)2); /* Arguments ignored. */ + if (ret != True) + cleanUpAndFail(1); +} diff --git a/exec/elfcore.c b/exec/elfcore.c new file mode 100644 index 00000000..523973d8 --- /dev/null +++ b/exec/elfcore.c @@ -0,0 +1,100 @@ +{ + processor_set_name_t pset; + host_t host; + processor_set_basic_info_data_t pinfo; + + thread_t *threads; + size_t nthreads; + + vm_address_t addr; + vm_size_t size; + vm_prot_t prot, maxprot; + vm_inherit_t inherit; + boolean_t shared; + memory_object_name_t objname; + vm_offset_t offset; + + /* Figure out what flavor of machine the task is on. */ + if (err = task_get_assignment (task, &pset)) + goto lose; + err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host, + &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT); + mach_port_deallocate (mach_task_self (), pset); + if (err) + goto lose; + err = bfd_mach_host_arch_mach (host, &arch, &machine, &e_machine); + mach_port_deallocate (mach_task_self (), host); + if (err) + goto lose; + + if (err = task_threads (task, &threads, &nthreads)) + goto lose; + + /* Create a BFD section to describe each contiguous chunk + of the task's address space with the same stats. */ + sec = NULL; + addr = 0; + while (!vm_region (task, &addr, &size, &prot, &maxprot, + &inherit, &shared, &objname, &offset)) + { + mach_port_deallocate (mach_task_self (), objname); + + if (prot != VM_PROT_NONE) + { + flagword flags = SEC_NO_FLAGS; + + if (!(prot & VM_PROT_WRITE)) + flags |= SEC_READONLY; + if (!(prot & VM_PROT_EXECUTE)) + flags |= SEC_DATA; + + if (sec != NULL && + (vm_address_t) (bfd_section_vma (bfd, sec) + + bfd_section_size (bfd, sec)) == addr && + flags == (bfd_get_section_flags (bfd, sec) & + (SEC_READONLY|SEC_DATA))) + /* Coalesce with the previous section. */ + bfd_set_section_size (bfd, sec, + bfd_section_size (bfd, sec) + size); + else + { + /* Make a new section (which might grow by + the next region being coalesced onto it). */ + char *name = bfd_intuit_section_name (addr, size, &flags); + if (name == NULL) + { + /* No guess from BFD. */ + if (asprintf (&name, "[%p,%p) %c%c%c", + (void *) addr, (void *) (addr + size), + (prot & VM_PROT_READ) ? 'r' : '-', + (prot & VM_PROT_WRITE) ? 'w' : '-', + (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1) + goto lose; + } + sec = bfd_make_section (name); + bfd_set_section_flags (bfd, sec, flags); + bfd_set_section_vma (bfd, sec, addr); + bfd_set_section_size (bfd, sec, size); + } + } + } + + /* Write all the sections' data. */ + for (sec = bfd->sections; sec != NULL; sec = sec->next) + { + void *data; + err = vm_read (task, bfd_section_vma (bfd, sec), + bfd_section_size (bfd, sec), &data); + if (err) + /* XXX What to do? + 1. lose + 2. remove this section + 3. mark this section as having ungettable contents (how?) + */ + goto lose; + err = bfd_set_section_contents (bfd, sec, data, 0, + bfd_section_size (bfd, sec)); + munmap ((caddr_t) data, bfd_section_size (bfd, sec)); + if (err) + goto bfdlose; + } diff --git a/exec/exec.c b/exec/exec.c new file mode 100644 index 00000000..02ca43f8 --- /dev/null +++ b/exec/exec.c @@ -0,0 +1,2065 @@ +/* GNU Hurd standard exec server. + Copyright (C) 1992,93,94,95,96,98,99 Free Software Foundation, Inc. + Written by Roland McGrath. + + Can exec ELF format directly. + #ifdef GZIP + Can gunzip executables into core on the fly. + #endif + #ifdef BFD + Can exec any executable format the BFD library understands + to be for this flavor of machine. + #endif + #ifdef BZIP2 + Can bunzip2 executables into core on the fly. + #endif + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#include "priv.h" +#include <hurd.h> +#include <hurd/exec.h> +#include <sys/stat.h> +#include <unistd.h> + +mach_port_t procserver; /* Our proc port. */ + +/* Standard exec data for secure execs. */ +mach_port_t *std_ports; +int *std_ints; +size_t std_nports, std_nints; +struct rwlock std_lock = RWLOCK_INITIALIZER; + + +#ifdef BFD +/* Return a Hurd error code corresponding to the most recent BFD error. */ +static error_t +b2he (error_t deflt) +{ + switch (bfd_get_error ()) + { + case bfd_error_system_call: + return errno; + + case bfd_error_no_memory: + return ENOMEM; + + default: + return deflt; + } +} +#else +#define b2he() a2he (errno) +#endif + +#ifdef GZIP +static void check_gzip (struct execdata *); +#endif + +#ifdef BZIP2 +static void check_bzip2 (struct execdata *); +#endif + +#ifdef BFD + +/* Check a section, updating the `locations' vector [BFD]. */ +static void +check_section (bfd *bfd, asection *sec, void *userdata) +{ + struct execdata *u = userdata; + vm_address_t addr; + static const union + { + char string[8]; + unsigned int quadword __attribute__ ((mode (DI))); + } interp = { string: ".interp" }; + + if (u->error) + return; + + /* Fast strcmp for this 8-byte constant string. */ + if (*(const __typeof (interp.quadword) *) sec->name == interp.quadword) + u->interp.section = sec; + + if (!(sec->flags & (SEC_ALLOC|SEC_LOAD)) || + (sec->flags & SEC_NEVER_LOAD)) + /* Nothing to do for this section. */ + return; + + addr = (vm_address_t) sec->vma; + + if (sec->flags & SEC_LOAD) + { + u->info.bfd_locations[sec->index] = sec->filepos; + if ((off_t) sec->filepos < 0 || (off_t) sec->filepos > u->file_size) + u->error = ENOEXEC; + } +} +#endif + + +/* Zero the specified region but don't crash the server if it faults. */ + +#include <hurd/sigpreempt.h> + +static error_t +safe_bzero (void *ptr, size_t size) +{ + return hurd_safe_memset (ptr, 0, size); +} + + +/* Load or allocate a section. */ +static void +load_section (void *section, struct execdata *u) +{ + vm_address_t addr = 0; + vm_offset_t filepos = 0; + vm_size_t filesz = 0, memsz = 0; + vm_prot_t vm_prot; + int anywhere; + vm_address_t mask = 0; +#ifdef BFD + asection *const sec = section; +#endif + const Elf32_Phdr *const ph = section; + + if (u->error) + return; + +#ifdef BFD + if (u->bfd && sec->flags & SEC_NEVER_LOAD) + /* Nothing to do for this section. */ + return; +#endif + + vm_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + +#ifdef BFD + if (u->bfd) + { + addr = (vm_address_t) sec->vma; + filepos = u->info.bfd_locations[sec->index]; + memsz = sec->_raw_size; + filesz = (sec->flags & SEC_LOAD) ? memsz : 0; + if (sec->flags & (SEC_READONLY|SEC_ROM)) + vm_prot &= ~VM_PROT_WRITE; + anywhere = 0; + } + else +#endif + { + addr = ph->p_vaddr & ~(ph->p_align - 1); + memsz = ph->p_vaddr + ph->p_memsz - addr; + filepos = ph->p_offset & ~(ph->p_align - 1); + filesz = ph->p_offset + ph->p_filesz - filepos; + if ((ph->p_flags & PF_R) == 0) + vm_prot &= ~VM_PROT_READ; + if ((ph->p_flags & PF_W) == 0) + vm_prot &= ~VM_PROT_WRITE; + if ((ph->p_flags & PF_X) == 0) + vm_prot &= ~VM_PROT_EXECUTE; + anywhere = u->info.elf.anywhere; + if (! anywhere) + addr += u->info.elf.loadbase; + else +#if 0 + switch (elf_machine) + { + case EM_386: + case EM_486: + /* On the i386, programs normally load at 0x08000000, and + expect their data segment to be able to grow dynamically + upward from its start near that address. We need to make + sure that the dynamic linker is not mapped in a conflicting + address. */ + /* mask = 0xf8000000UL; */ /* XXX */ + break; + default: + break; + } +#endif + if (anywhere && addr < vm_page_size) + addr = vm_page_size; + } + + if (memsz == 0) + /* This section is empty; ignore it. */ + return; + + if (filesz != 0) + { + vm_address_t mapstart = round_page (addr); + + /* Allocate space in the task and write CONTENTS into it. */ + void write_to_task (vm_address_t mapstart, vm_size_t size, + vm_prot_t vm_prot, vm_address_t contents) + { + vm_size_t off = size % vm_page_size; + /* Allocate with vm_map to set max protections. */ + u->error = vm_map (u->task, + &mapstart, size, mask, anywhere, + MACH_PORT_NULL, 0, 1, + vm_prot|VM_PROT_WRITE, + VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, + VM_INHERIT_COPY); + if (! u->error && size >= vm_page_size) + u->error = vm_write (u->task, mapstart, contents, size - off); + if (! u->error && off != 0) + { + vm_address_t page = 0; + page = (vm_address_t) mmap (0, vm_page_size, + PROT_READ|PROT_WRITE, MAP_ANON, + 0, 0); + u->error = (page == -1) ? errno : 0; + if (! u->error) + { + memcpy ((void *) page, + (void *) (contents + (size - off)), + off); + u->error = vm_write (u->task, mapstart + (size - off), + page, vm_page_size); + munmap ((caddr_t) page, vm_page_size); + } + } + /* Reset the current protections to the desired state. */ + if (! u->error && (vm_prot & VM_PROT_WRITE) == 0) + u->error = vm_protect (u->task, mapstart, size, 0, vm_prot); + } + + if (mapstart - addr < filesz) + { + /* MAPSTART is the first page that starts inside the section. + Map all the pages that start inside the section. */ + +#define SECTION_IN_MEMORY_P (u->file_data != NULL) +#define SECTION_CONTENTS (u->file_data + filepos) + if (SECTION_IN_MEMORY_P) + /* Data is already in memory; write it into the task. */ + write_to_task (mapstart, filesz - (mapstart - addr), vm_prot, + (vm_address_t) SECTION_CONTENTS + + (mapstart - addr)); + else if (u->filemap != MACH_PORT_NULL) + /* Map the data into the task directly from the file. */ + u->error = vm_map (u->task, + &mapstart, filesz - (mapstart - addr), + mask, anywhere, + u->filemap, filepos + (mapstart - addr), 1, + vm_prot, + VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, + VM_INHERIT_COPY); + else + { + /* Cannot map the data. Read it into a buffer and vm_write + it into the task. */ + void *buf; + const vm_size_t size = filesz - (mapstart - addr); + buf = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + u->error = (buf == (caddr_t) -1) ? errno : 0; + if (! u->error) + { + if (fseek (&u->stream, + filepos + (mapstart - addr), SEEK_SET) || + fread (buf, size, 1, &u->stream) != 1) + u->error = errno; + else + write_to_task (mapstart, size, vm_prot, + (vm_address_t) buf); + munmap (buf, size); + } + } + if (u->error) + return; + + if (anywhere) + { + /* We let the kernel choose the location of the mapping. + Now record where it ended up. Later sections cannot + be mapped anywhere, they must come after this one. */ + u->info.elf.loadbase = mapstart; + addr = mapstart + (addr % vm_page_size); + anywhere = u->info.elf.anywhere = 0; + mask = 0; + } + } + + if (mapstart > addr) + { + /* We must read and copy in the space in the section before the + first page boundary. */ + vm_address_t overlap_page = trunc_page (addr); + vm_address_t ourpage = 0; + vm_size_t size = 0; + void *readaddr; + size_t readsize; + + u->error = vm_read (u->task, overlap_page, vm_page_size, + &ourpage, &size); + if (u->error) + { + if (u->error == KERN_INVALID_ADDRESS) + { + /* The space is unallocated. */ + u->error = vm_allocate (u->task, + &overlap_page, vm_page_size, 0); + size = vm_page_size; + if (!u->error) + { + ourpage = (vm_address_t) mmap (0, vm_page_size, + PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + u->error = (ourpage == -1) ? errno : 0; + } + } + if (u->error) + { + maplose: + vm_deallocate (u->task, mapstart, filesz); + return; + } + } + + readaddr = (void *) (ourpage + (addr - overlap_page)); + readsize = size - (addr - overlap_page); + if (readsize > filesz) + readsize = filesz; + + if (SECTION_IN_MEMORY_P) + bcopy (SECTION_CONTENTS, readaddr, readsize); + else + if (fseek (&u->stream, filepos, SEEK_SET) || + fread (readaddr, readsize, 1, &u->stream) != 1) + { + u->error = errno; + goto maplose; + } + u->error = vm_write (u->task, overlap_page, ourpage, size); + if (u->error == KERN_PROTECTION_FAILURE) + { + /* The overlap page is not writable; the section + that appears in preceding memory is read-only. + Change the page's protection so we can write it. */ + u->error = vm_protect (u->task, overlap_page, size, + 0, vm_prot | VM_PROT_WRITE); + if (!u->error) + u->error = vm_write (u->task, overlap_page, ourpage, size); + /* If this section is not supposed to be writable either, + restore the page's protection to read-only. */ + if (!u->error && !(vm_prot & VM_PROT_WRITE)) + u->error = vm_protect (u->task, overlap_page, size, + 0, vm_prot); + } + munmap ((caddr_t) ourpage, size); + if (u->error) + goto maplose; + } + + if (u->cntl) + u->cntl->accessed = 1; + + /* Tell the code below to zero-fill the remaining area. */ + addr += filesz; + memsz -= filesz; + } + + if (memsz != 0) + { + /* SEC_ALLOC: Allocate zero-filled memory for the section. */ + + vm_address_t mapstart = round_page (addr); + + if (mapstart - addr < memsz) + { + /* MAPSTART is the first page that starts inside the section. + Allocate all the pages that start inside the section. */ + u->error = vm_map (u->task, &mapstart, memsz - (mapstart - addr), + mask, anywhere, MACH_PORT_NULL, 0, 1, + vm_prot, VM_PROT_ALL, VM_INHERIT_COPY); + if (u->error) + return; + } + + if (anywhere) + { + /* We let the kernel choose the location of the zero space. + Now record where it ended up. Later sections cannot + be mapped anywhere, they must come after this one. */ + u->info.elf.loadbase = mapstart; + addr = mapstart + (addr % vm_page_size); + anywhere = u->info.elf.anywhere = 0; + mask = 0; + } + + if (mapstart > addr) + { + /* Zero space in the section before the first page boundary. */ + vm_address_t overlap_page = trunc_page (addr); + vm_address_t ourpage = 0; + vm_size_t size = 0; + u->error = vm_read (u->task, overlap_page, vm_page_size, + &ourpage, &size); + if (u->error) + { + vm_deallocate (u->task, mapstart, memsz); + return; + } + u->error = safe_bzero ((void *) (ourpage + (addr - overlap_page)), + size - (addr - overlap_page)); + if (! u->error && !(vm_prot & VM_PROT_WRITE)) + u->error = vm_protect (u->task, overlap_page, size, + 0, VM_PROT_WRITE); + if (! u->error) + u->error = vm_write (u->task, overlap_page, ourpage, size); + if (! u->error && !(vm_prot & VM_PROT_WRITE)) + u->error = vm_protect (u->task, overlap_page, size, 0, vm_prot); + munmap ((caddr_t) ourpage, size); + } + } +} + +/* Make sure our mapping window (or read buffer) covers + LEN bytes of the file starting at POSN. */ + +static void * +map (struct execdata *e, off_t posn, size_t len) +{ + FILE *f = &e->stream; + const size_t size = e->file_size; + size_t offset; + + if ((f->__offset & ~(f->__bufsize - 1)) == (posn & ~(f->__bufsize - 1)) && + f->__buffer + (posn + len - f->__offset) < f->__get_limit) + /* The current mapping window covers it. */ + offset = posn & (f->__bufsize - 1); + else if (e->filemap == MACH_PORT_NULL) + { + /* No mapping for the file. Read the data by RPC. */ + char *buffer = f->__buffer; + mach_msg_type_number_t nread = f->__bufsize; + /* Read as much as we can get into the buffer right now. */ + e->error = io_read (e->file, &buffer, &nread, posn, round_page (len)); + if (e->error) + { + errno = e->error; + f->__error = 1; + return NULL; + } + if (buffer != f->__buffer) + { + /* The data was returned out of line. Discard the old buffer. */ + if (f->__bufsize != 0) + munmap (f->__buffer, f->__bufsize); + f->__buffer = buffer; + f->__bufsize = round_page (nread); + } + + f->__offset = posn; + f->__get_limit = f->__buffer + nread; + offset = 0; + } + else + { + /* Deallocate the old mapping area. */ + if (f->__buffer != NULL) + munmap (f->__buffer, f->__bufsize); + f->__buffer = NULL; + + /* Make sure our mapping is page-aligned in the file. */ + offset = posn & (vm_page_size - 1); + f->__offset = trunc_page (posn); + f->__bufsize = round_page (posn + len) - f->__offset; + + /* Map the data from the file. */ + if (vm_map (mach_task_self (), + (vm_address_t *) &f->__buffer, f->__bufsize, 0, 1, + e->filemap, f->__offset, 1, VM_PROT_READ, VM_PROT_READ, + VM_INHERIT_NONE)) + { + errno = e->error = EIO; + f->__error = 1; + return NULL; + } + + if (e->cntl) + e->cntl->accessed = 1; + + if (f->__offset + f->__bufsize > size) + f->__get_limit = f->__buffer + (size - f->__offset); + else + f->__get_limit = f->__buffer + f->__bufsize; + } + + f->__target = f->__offset; + f->__bufp = f->__buffer + offset; + + if (f->__bufp + len > f->__get_limit) + { + f->__eof = 1; + return NULL; + } + + return f->__bufp; +} + +/* stdio input-room function. */ +static int +input_room (FILE *f) +{ + return (map (f->__cookie, f->__target, 1) == NULL ? EOF : + (unsigned char) *f->__bufp++); +} + +static int +close_exec_stream (void *cookie) +{ + struct execdata *e = cookie; + + if (e->stream.__buffer != NULL) + munmap (e->stream.__buffer, e->stream.__bufsize); + + return 0; +} + +/* stdio seek function. */ +static int +fake_seek (void *cookie, fpos_t *pos, int whence) +{ + struct execdata *e = cookie; + + /* Set __target to match the specifed seek location */ + switch (whence) + { + case SEEK_END: + e->stream.__target = e->file_size + *pos; + break; + + case SEEK_CUR: + e->stream.__target += *pos; + break; + + case SEEK_SET: + e->stream.__target = *pos; + break; + } + *pos = e->stream.__target; + return 0; +} + + +/* Prepare to check and load FILE. */ +static void +prepare (file_t file, struct execdata *e) +{ + memory_object_t rd, wr; + + e->file = file; + +#ifdef BFD + e->bfd = NULL; +#endif + e->file_data = NULL; + e->cntl = NULL; + e->filemap = MACH_PORT_NULL; + e->cntlmap = MACH_PORT_NULL; + + e->interp.section = NULL; + + /* Initialize E's stdio stream. */ + memset (&e->stream, 0, sizeof (e->stream)); + e->stream.__magic = _IOMAGIC; + e->stream.__mode.__read = 1; + e->stream.__userbuf = 1; + e->stream.__room_funcs.__input = input_room; + e->stream.__io_funcs.seek = fake_seek; + e->stream.__io_funcs.close = close_exec_stream; + e->stream.__cookie = e; + e->stream.__seen = 1; + + /* Try to mmap FILE. */ + e->error = io_map (file, &rd, &wr); + if (! e->error) + /* Mapping is O.K. */ + { + if (wr != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), wr); + if (rd == MACH_PORT_NULL) + { + e->error = EBADF; /* ? XXX */ + return; + } + e->filemap = rd; + + e->error = /* io_map_cntl (file, &e->cntlmap) */ EOPNOTSUPP; /* XXX */ + if (e->error) + { + /* No shared page. Do a stat to find the file size. */ + struct stat st; + e->error = io_stat (file, &st); + if (e->error) + return; + e->file_size = st.st_size; + e->optimal_block = st.st_blksize; + } + else + e->error = vm_map (mach_task_self (), (vm_address_t *) &e->cntl, + vm_page_size, 0, 1, e->cntlmap, 0, 0, + VM_PROT_READ|VM_PROT_WRITE, + VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE); + + if (e->cntl) + while (1) + { + spin_lock (&e->cntl->lock); + switch (e->cntl->conch_status) + { + case USER_COULD_HAVE_CONCH: + e->cntl->conch_status = USER_HAS_CONCH; + case USER_HAS_CONCH: + spin_unlock (&e->cntl->lock); + /* Break out of the loop. */ + break; + case USER_RELEASE_CONCH: + case USER_HAS_NOT_CONCH: + default: /* Oops. */ + spin_unlock (&e->cntl->lock); + e->error = io_get_conch (e->file); + if (e->error) + return; + /* Continue the loop. */ + continue; + } + + /* Get here if we are now IT. */ + e->file_size = 0; + if (e->cntl->use_file_size) + e->file_size = e->cntl->file_size; + if (e->cntl->use_read_size && e->cntl->read_size > e->file_size) + e->file_size = e->cntl->read_size; + break; + } + } + else if (e->error == EOPNOTSUPP) + /* We can't mmap FILE, but perhaps we can do normal I/O to it. */ + e->error = 0; +} + +/* Check the magic number, etc. of the file. + On successful return, the caller must allocate the + E->locations vector, and map check_section over the BFD. */ + +#ifdef BFD +static void +check_bfd (struct execdata *e) +{ + bfd_set_error (bfd_error_no_error); + + e->bfd = bfd_openstreamr (NULL, NULL, &e->stream); + if (e->bfd == NULL) + { + e->error = b2he (ENOEXEC); + return; + } + + if (!bfd_check_format (e->bfd, bfd_object)) + { + e->error = b2he (ENOEXEC); + return; + } + else if (/* !(e->bfd->flags & EXEC_P) || XXX */ + (host_bfd.arch_info->compatible = e->bfd->arch_info->compatible, + bfd_arch_get_compatible (&host_bfd, e->bfd)) != host_bfd.arch_info) + { + /* This file is of a recognized binary file format, but it is not + executable on this machine. */ + e->error = b2he (ENOEXEC); + return; + } + + e->entry = e->bfd->start_address; +} +#endif + +#include <endian.h> +#if BYTE_ORDER == BIG_ENDIAN +#define host_ELFDATA ELFDATA2MSB +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#define host_ELFDATA ELFDATA2LSB +#endif + +static void +check_elf (struct execdata *e) +{ + Elf32_Ehdr *ehdr = map (e, 0, sizeof (Elf32_Ehdr)); + Elf32_Phdr *phdr; + + if (! ehdr) + { + if (! ferror (&e->stream)) + e->error = ENOEXEC; + return; + } + + if (*(Elf32_Word *) ehdr != ((union { Elf32_Word word; + unsigned char string[SELFMAG]; }) + { string: ELFMAG }).word) + { + e->error = ENOEXEC; + return; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_ident[EI_DATA] != host_ELFDATA || + ehdr->e_ident[EI_VERSION] != EV_CURRENT || + ehdr->e_version != EV_CURRENT || + ehdr->e_ehsize < sizeof *ehdr || + ehdr->e_phentsize != sizeof (Elf32_Phdr)) + { + e->error = ENOEXEC; + return; + } + e->error = elf_machine_matches_host (ehdr->e_machine); + if (e->error) + return; + + /* Extract all this information now, while EHDR is mapped. + The `map' call below for the phdrs may reuse the mapping window. */ + e->entry = ehdr->e_entry; + e->info.elf.anywhere = (ehdr->e_type == ET_DYN || + ehdr->e_type == ET_REL); + e->info.elf.loadbase = 0; + e->info.elf.phnum = ehdr->e_phnum; + + phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr)); + if (! phdr) + { + if (! ferror (&e->stream)) + e->error = ENOEXEC; + return; + } + e->info.elf.phdr = phdr; +} + +static void +check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr, + vm_address_t *phdr_addr, vm_size_t *phdr_size) +{ + const Elf32_Phdr *phdr; + + memcpy (e->info.elf.phdr, mapped_phdr, + e->info.elf.phnum * sizeof (Elf32_Phdr)); + + for (phdr = e->info.elf.phdr; + phdr < &e->info.elf.phdr[e->info.elf.phnum]; + ++phdr) + switch (phdr->p_type) + { + case PT_INTERP: + e->interp.phdr = phdr; + break; + case PT_PHDR: + if (phdr_addr) + *phdr_addr = phdr->p_vaddr & ~(phdr->p_align - 1); + if (phdr_size) + *phdr_size = phdr->p_memsz; + break; + case PT_LOAD: + /* Sanity check. */ + if (e->file_size <= (off_t) (phdr->p_offset + + phdr->p_filesz)) + e->error = ENOEXEC; + break; + } +} + + +static void +check (struct execdata *e) +{ + check_elf (e); +#ifdef BFD + if (e->error == ENOEXEC) + { + e->error = 0; + check_bfd (e); + } +#endif +} + + +/* Release the conch and clean up mapping the file and control page. */ +static void +finish_mapping (struct execdata *e) +{ + if (e->cntl != NULL) + { + spin_lock (&e->cntl->lock); + if (e->cntl->conch_status == USER_RELEASE_CONCH) + { + spin_unlock (&e->cntl->lock); + io_release_conch (e->file); + } + else + { + e->cntl->conch_status = USER_HAS_NOT_CONCH; + spin_unlock (&e->cntl->lock); + } + munmap (e->cntl, vm_page_size); + e->cntl = NULL; + } + if (e->filemap != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), e->filemap); + e->filemap = MACH_PORT_NULL; + } + if (e->cntlmap != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), e->cntlmap); + e->cntlmap = MACH_PORT_NULL; + } +} + +/* Clean up after reading the file (need not be completed). */ +void +finish (struct execdata *e, int dealloc_file) +{ + finish_mapping (e); +#ifdef BFD + if (e->bfd != NULL) + { + bfd_close (e->bfd); + e->bfd = NULL; + } + else +#endif + fclose (&e->stream); + if (dealloc_file && e->file != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), e->file); + e->file = MACH_PORT_NULL; + } +} + + +/* Load the file. */ +static void +load (task_t usertask, struct execdata *e) +{ + e->task = usertask; + + if (! e->error) + { +#ifdef BFD + if (e->bfd) + { + void load_bfd_section (bfd *bfd, asection *sec, void *userdata) + { + load_section (sec, userdata); + } + bfd_map_over_sections (e->bfd, &load_bfd_section, e); + } + else +#endif + { + Elf32_Word i; + for (i = 0; i < e->info.elf.phnum; ++i) + if (e->info.elf.phdr[i].p_type == PT_LOAD) + load_section (&e->info.elf.phdr[i], e); + + /* The entry point address is relative to whereever we loaded the + program text. */ + e->entry += e->info.elf.loadbase; + } + } + + /* Release the conch for the file. */ + finish_mapping (e); + + if (! e->error) + { + /* Do post-loading processing on the task. */ + +#ifdef BFD + if (e->bfd) + { + /* Do post-loading processing for a section. This consists of + peeking the pages of non-demand-paged executables. */ + + void postload_section (bfd *bfd, asection *sec, void *userdata) + { + struct execdata *u = userdata; + vm_address_t addr = 0; + vm_size_t secsize = 0; + + addr = (vm_address_t) sec->vma; + secsize = sec->_raw_size; + + if ((sec->flags & SEC_LOAD) && !(bfd->flags & D_PAGED)) + { + /* Pre-load the section by peeking every mapped page. */ + vm_address_t myaddr, a; + vm_size_t mysize; + myaddr = 0; + + /* We have already mapped the file into the task in + load_section. Now read from the task's memory into our + own address space so we can peek each page and cause it to + be paged in. */ + u->error = vm_read (u->task, trunc_page (addr), + round_page (secsize), &myaddr, &mysize); + if (u->error) + return; + + /* Peek at the first word of each page. */ + for (a = ((myaddr + mysize) & ~(vm_page_size - 1)); + a >= myaddr; a -= vm_page_size) + /* Force it to be paged in. */ + (void) *(volatile int *) a; + + munmap ((caddr_t) myaddr, mysize); + } + } + + bfd_map_over_sections (e->bfd, postload_section, e); + } +#endif + } +} + +#ifdef GZIP +/* Check the file for being a gzip'd image. Return with ENOEXEC means not + a valid gzip file; return with another error means lossage in decoding; + return with zero means the file was uncompressed into memory which E now + points to, and `check' can be run again. */ + +static void +check_gzip (struct execdata *earg) +{ + struct execdata *e = earg; + /* Entry points to unzip engine. */ + int get_method (int); + void unzip (int, int); + extern long int bytes_out; + /* Callbacks from unzip for I/O and error interface. */ + extern int (*unzip_read) (char *buf, size_t maxread); + extern void (*unzip_write) (const char *buf, size_t nwrite); + extern void (*unzip_read_error) (void); + extern void (*unzip_error) (const char *msg); + + char *zipdata = NULL; + size_t zipdatasz = 0; + FILE *zipout = NULL; + jmp_buf ziperr; + int zipread (char *buf, size_t maxread) + { + return fread (buf, 1, maxread, &e->stream); + } + void zipwrite (const char *buf, size_t nwrite) + { + if (fwrite (buf, nwrite, 1, zipout) != 1) + longjmp (ziperr, 1); + } + void ziprderr (void) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + void ziperror (const char *msg) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + + unzip_read = zipread; + unzip_write = zipwrite; + unzip_read_error = ziprderr; + unzip_error = ziperror; + + if (setjmp (ziperr)) + { + /* Error in unzipping jumped out. */ + if (zipout) + { + fclose (zipout); + free (zipdata); + } + e->error = errno; + return; + } + + rewind (&e->stream); + if (get_method (0) != 0) + { + /* Not a happy gzip file. */ + e->error = ENOEXEC; + return; + } + + /* Matched gzip magic number. Ready to unzip. + Set up the output stream and let 'er rip. */ + + zipout = open_memstream (&zipdata, &zipdatasz); + if (! zipout) + { + e->error = errno; + return; + } + + /* Call the gunzip engine. */ + bytes_out = 0; + unzip (17, 23); /* Arguments ignored. */ + + /* The output is complete. Clean up the stream and store its resultant + buffer and size in the execdata as the file contents. */ + fclose (zipout); + e->file_data = zipdata; + e->file_size = zipdatasz; + + /* Clean up the old exec file stream's state. */ + finish (e, 0); + + /* Point the stream at the buffer of file data. */ + memset (&e->stream, 0, sizeof (e->stream)); + e->stream.__magic = _IOMAGIC; + e->stream.__mode.__read = 1; + e->stream.__buffer = e->file_data; + e->stream.__bufsize = e->file_size; + e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize; + e->stream.__bufp = e->stream.__buffer; + e->stream.__seen = 1; +} +#endif + +#ifdef BZIP2 +/* Check the file for being a bzip2'd image. Return with ENOEXEC means not + a valid bzip2 file; return with another error means lossage in decoding; + return with zero means the file was uncompressed into memory which E now + points to, and `check' can be run again. */ + +static void +check_bzip2 (struct execdata *earg) +{ + struct execdata *e = earg; + /* Entry points to bunzip2 engine. */ + void do_bunzip2 (void); + /* Callbacks from unzip for I/O and error interface. */ + extern int (*unzip_read) (char *buf, size_t maxread); + extern void (*unzip_write) (const char *buf, size_t nwrite); + extern void (*unzip_read_error) (void); + extern void (*unzip_error) (const char *msg); + + char *zipdata = NULL; + size_t zipdatasz = 0; + FILE *zipout = NULL; + jmp_buf ziperr; + int zipread (char *buf, size_t maxread) + { + return fread (buf, 1, maxread, &e->stream); + } + void zipwrite (const char *buf, size_t nwrite) + { + if (fwrite (buf, nwrite, 1, zipout) != 1) + longjmp (ziperr, 1); + } + void ziprderr (void) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + void ziperror (const char *msg) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + + unzip_read = zipread; + unzip_write = zipwrite; + unzip_read_error = ziprderr; + unzip_error = ziperror; + + if (setjmp (ziperr)) + { + /* Error in unzipping jumped out. */ + if (zipout) + { + fclose (zipout); + free (zipdata); + } + e->error = errno; + return; + } + + rewind (&e->stream); + + zipout = open_memstream (&zipdata, &zipdatasz); + if (! zipout) + { + e->error = errno; + return; + } + + /* Call the bunzip2 engine. */ + do_bunzip2 (); + + /* The output is complete. Clean up the stream and store its resultant + buffer and size in the execdata as the file contents. */ + fclose (zipout); + e->file_data = zipdata; + e->file_size = zipdatasz; + + /* Clean up the old exec file stream's state. */ + finish (e, 0); + + /* Point the stream at the buffer of file data. */ + memset (&e->stream, 0, sizeof (e->stream)); + e->stream.__magic = _IOMAGIC; + e->stream.__mode.__read = 1; + e->stream.__buffer = e->file_data; + e->stream.__bufsize = e->file_size; + e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize; + e->stream.__bufp = e->stream.__buffer; + e->stream.__seen = 1; +} +#endif + + +static inline error_t +servercopy (void **arg, mach_msg_type_number_t argsize, boolean_t argcopy) +{ + if (argcopy) + { + /* ARG came in-line, so we must copy it. */ + void *copy; + copy = mmap (0, argsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (copy == (void *) -1) + return errno; + bcopy (*arg, copy, argsize); + *arg = copy; + } + return 0; +} + + +static error_t +do_exec (file_t file, + task_t oldtask, + int flags, + char *argv, mach_msg_type_number_t argvlen, boolean_t argv_copy, + char *envp, mach_msg_type_number_t envplen, boolean_t envp_copy, + mach_port_t *dtable, mach_msg_type_number_t dtablesize, + boolean_t dtable_copy, + mach_port_t *portarray, mach_msg_type_number_t nports, + boolean_t portarray_copy, + int *intarray, mach_msg_type_number_t nints, boolean_t intarray_copy, + mach_port_t *deallocnames, mach_msg_type_number_t ndeallocnames, + mach_port_t *destroynames, mach_msg_type_number_t ndestroynames) +{ + struct execdata e, interp; + task_t newtask = MACH_PORT_NULL; + thread_t thread = MACH_PORT_NULL; + struct bootinfo *boot = 0; + int *ports_replaced; + int secure, defaults; + vm_address_t phdr_addr = 0; + vm_size_t phdr_size = 0; + mach_msg_type_number_t i; + int intarray_dealloc = 0; /* Dealloc INTARRAY before returning? */ + int oldtask_trashed = 0; /* Have we trashed the old task? */ + + /* Prime E for executing FILE and check its validity. This must be an + inline function because it stores pointers into alloca'd storage in E + for later use in `load'. */ + void prepare_and_check (file_t file, struct execdata *e) + { + /* Prepare E to read the file. */ + prepare (file, e); + if (e->error) + return; + + /* Check the file for validity first. */ + check (e); + +#ifdef GZIP + if (e->error == ENOEXEC) + { + /* See if it is a compressed image. */ + static struct mutex lock = MUTEX_INITIALIZER; + /* The gzip code is really cheesy, not even close to thread-safe. + So we serialize all uses of it. */ + mutex_lock (&lock); + e->error = 0; + check_gzip (e); + mutex_unlock (&lock); + if (e->error == 0) + /* The file was uncompressed into memory, and now E describes the + uncompressed image rather than the actual file. Check it again + for a valid magic number. */ + check (e); + } +#endif +#ifdef BZIP2 + if (e->error == ENOEXEC) + { + /* See if it is a compressed image. */ + static struct mutex lock = MUTEX_INITIALIZER; + /* The bzip2 code is really cheesy, not even close to thread-safe. + So we serialize all uses of it. */ + mutex_lock (&lock); + e->error = 0; + check_bzip2 (e); + mutex_unlock (&lock); + if (e->error == 0) + /* The file was uncompressed into memory, and now E describes the + uncompressed image rather than the actual file. Check it again + for a valid magic number. */ + check (e); + } +#endif + } + + + /* Here is the main body of the function. */ + + + /* Catch this error now, rather than later. */ + /* XXX For EXEC_DEFAULTS, this is only an error if one of the user's + ports is null; if they are all provided, then EXEC_DEFAULTS would + have no effect, and the lack of installed standard ports should + not cause an error. -mib */ + if ((!std_ports || !std_ints) && (flags & (EXEC_SECURE|EXEC_DEFAULTS))) + return EIEIO; + + /* Suspend the existing task before frobnicating it. */ + if (oldtask != MACH_PORT_NULL && (e.error = task_suspend (oldtask))) + return e.error; + + /* Prime E for executing FILE and check its validity. */ + prepare_and_check (file, &e); + + if (e.error == ENOEXEC) + { + /* Check for a #! executable file. */ + check_hashbang (&e, + file, oldtask, flags, + argv, argvlen, argv_copy, + envp, envplen, envp_copy, + dtable, dtablesize, dtable_copy, + portarray, nports, portarray_copy, + intarray, nints, intarray_copy, + deallocnames, ndeallocnames, + destroynames, ndestroynames); + if (! e.error) + /* The #! exec succeeded; nothing more to do. */ + return 0; + } + + if (e.error) + /* The file is not a valid executable. */ + goto out; + +#ifdef BFD + if (e.bfd) + { + e.info.bfd_locations = alloca (e.bfd->section_count * + sizeof (vm_offset_t)); + bfd_map_over_sections (e.bfd, check_section, &e); + } + else +#endif + { + const Elf32_Phdr *phdr = e.info.elf.phdr; + e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (Elf32_Phdr)); + check_elf_phdr (&e, phdr, &phdr_addr, &phdr_size); + } + + interp.file = MACH_PORT_NULL; + + if (oldtask == MACH_PORT_NULL) + flags |= EXEC_NEWTASK; + + if (flags & (EXEC_NEWTASK|EXEC_SECURE)) + { + /* Create the new task. If we are not being secure, then use OLDTASK + for the task_create RPC, in case it is something magical. */ + e.error = task_create (((flags & EXEC_SECURE) || + oldtask == MACH_PORT_NULL) ? + mach_task_self () : oldtask, + 0, &newtask); + if (e.error) + goto out; + } + else + newtask = oldtask; + + + rwlock_reader_lock (&std_lock); + { + /* Store the data that we will give in response + to the RPC on the new task's bootstrap port. */ + + /* Set boot->portarray[IDX] to NEW. If REAUTH is nonzero, + io_reauthenticate NEW and set it to the authenticated port. + If CONSUME is nonzero, a reference on NEW is consumed; + it is invalid to give nonzero values to both REAUTH and CONSUME. */ +#define use(idx, new, reauth, consume) \ + do { use1 (idx, new, reauth, consume); \ + if (e.error) goto stdout; } while (0) + void use1 (unsigned int idx, mach_port_t new, + int reauth, int consume) + { + if (new != MACH_PORT_NULL && reauth) + { + mach_port_t ref = mach_reply_port (), authed; + e.error = io_reauthenticate (new, ref, MACH_MSG_TYPE_MAKE_SEND); + if (! e.error) + e.error = auth_user_authenticate + (boot->portarray[INIT_PORT_AUTH], + ref, MACH_MSG_TYPE_MAKE_SEND, &authed); + mach_port_destroy (mach_task_self (), ref); + if (e.error) + return; + new = authed; + } + else + { + if (!consume && new != MACH_PORT_NULL) + mach_port_mod_refs (mach_task_self (), + new, MACH_PORT_RIGHT_SEND, 1); + } + + boot->portarray[idx] = new; + ports_replaced[idx] = 1; + } + + e.error = ports_create_port (execboot_portclass, port_bucket, + sizeof *boot, &boot); + if (boot == NULL) + { + stdout: + rwlock_reader_unlock (&std_lock); + goto out; + } + bzero (&boot->pi + 1, (char *) &boot[1] - (char *) (&boot->pi + 1)); + + /* These flags say the information we pass through to the new program + may need to be modified. */ + secure = (flags & EXEC_SECURE); + defaults = (flags & EXEC_DEFAULTS); + + /* Now record the big blocks of data we shuffle around unchanged. + Whatever arrived inline, we must allocate space for so it can + survive after this RPC returns. */ + + boot->flags = flags; + + e.error = servercopy ((void **) &argv, argvlen, argv_copy); + if (e.error) + goto stdout; + boot->argv = argv; + boot->argvlen = argvlen; + e.error = servercopy ((void **) &envp, envplen, envp_copy); + if (e.error) + goto stdout; + boot->envp = envp; + boot->envplen = envplen; + e.error = servercopy ((void **) &dtable, dtablesize * sizeof (mach_port_t), + dtable_copy); + if (e.error) + goto stdout; + boot->dtable = dtable; + boot->dtablesize = dtablesize; + + if ((secure || defaults) && nints < INIT_INT_MAX) + { + /* Make sure the intarray is at least big enough. */ + if (intarray_copy || (round_page (nints * sizeof (int)) < + round_page (INIT_INT_MAX * sizeof (int)))) + { + /* Allocate a new vector that is big enough. */ + boot->intarray = mmap (0, INIT_INT_MAX * sizeof (int), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + memcpy (boot->intarray, intarray, nints * sizeof (int)); + intarray_dealloc = !intarray_copy; + } + else + boot->intarray = intarray; + boot->nints = INIT_INT_MAX; + } + else + { + e.error = servercopy ((void **) &intarray, nints * sizeof (int), + intarray_copy); + if (e.error) + goto stdout; + boot->intarray = intarray; + boot->nints = nints; + } + + if (secure) + boot->intarray[INIT_UMASK] = std_ints ? std_ints[INIT_UMASK] : CMASK; + + /* Now choose the ports to give the new program. */ + + boot->nports = nports < INIT_PORT_MAX ? INIT_PORT_MAX : nports; + boot->portarray = mmap (0, boot->nports * sizeof (mach_port_t), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + /* Start by copying the array as passed. */ + for (i = 0; i < nports; ++i) + boot->portarray[i] = portarray[i]; + if (MACH_PORT_NULL != 0) + for (; i < boot->nports; ++i) + boot->portarray[i] = MACH_PORT_NULL; + /* Keep track of which ports in BOOT->portarray come from the original + PORTARRAY, and which we replace. */ + ports_replaced = alloca (boot->nports * sizeof *ports_replaced); + bzero (ports_replaced, boot->nports * sizeof *ports_replaced); + + if (portarray[INIT_PORT_BOOTSTRAP] == MACH_PORT_NULL && + oldtask != MACH_PORT_NULL) + { + if (! task_get_bootstrap_port (oldtask, + &boot->portarray[INIT_PORT_BOOTSTRAP])) + ports_replaced[INIT_PORT_BOOTSTRAP] = 1; + } + + /* Note that the parentheses on this first test are different from the + others below it. */ + if ((secure || defaults) + && boot->portarray[INIT_PORT_AUTH] == MACH_PORT_NULL) + /* Q: Doesn't this let anyone run a program and make it + get a root auth port? + A: No; the standard port for INIT_PORT_AUTH has no UID's at all. + See init.trim/init.c (init_stdarrays). */ + use (INIT_PORT_AUTH, std_ports[INIT_PORT_AUTH], 0, 0); + if (secure || (defaults + && boot->portarray[INIT_PORT_PROC] == MACH_PORT_NULL)) + { + /* Ask the proc server for the proc port for this task. */ + mach_port_t new; + + e.error = proc_task2proc (procserver, newtask, &new); + if (e.error) + goto stdout; + use (INIT_PORT_PROC, new, 0, 1); + } + else if (oldtask != newtask && oldtask != MACH_PORT_NULL + && boot->portarray[INIT_PORT_PROC] != MACH_PORT_NULL) + { + mach_port_t new; + /* This task port refers to the old task; use it to fetch a new + one for the new task. */ + e.error = proc_task2proc (boot->portarray[INIT_PORT_PROC], + newtask, &new); + if (e.error) + goto stdout; + use (INIT_PORT_PROC, new, 0, 1); + } + if (secure || (defaults + && boot->portarray[INIT_PORT_CRDIR] == MACH_PORT_NULL)) + use (INIT_PORT_CRDIR, std_ports[INIT_PORT_CRDIR], 1, 0); + if ((secure || defaults) + && boot->portarray[INIT_PORT_CWDIR] == MACH_PORT_NULL) + use (INIT_PORT_CWDIR, std_ports[INIT_PORT_CWDIR], 1, 0); + } + rwlock_reader_unlock (&std_lock); + + + /* We have now concocted in BOOT the complete Hurd context (ports and + ints) that the new program image will run under. We will use these + ports for looking up the interpreter file if there is one. */ + + if (! e.error && e.interp.section) + { + /* There is an interpreter section specifying another file to load + along with this executable. Find the name of the file and open + it. */ + +#ifdef BFD + char namebuf[e.bfd ? e.interp.section->_raw_size : 0]; +#endif + char *name; + +#ifdef BFD + if (e.bfd) + { + if (! bfd_get_section_contents (e.bfd, e.interp.section, + namebuf, 0, + e.interp.section->_raw_size)) + { + e.error = b2he (errno); + name = NULL; + } + else + name = namebuf; + } + else +#endif + { + name = map (&e, (e.interp.phdr->p_offset + & ~(e.interp.phdr->p_align - 1)), + e.interp.phdr->p_filesz); + if (! name && ! ferror (&e.stream)) + e.error = ENOEXEC; + } + + if (! name) + e.interp.section = NULL; + else + { + /* Open the named file using the appropriate directory ports for + the user. */ + error_t user_port (int which, error_t (*operate) (mach_port_t)) + { + return (*operate) (boot->nports > which ? + boot->portarray[which] : + MACH_PORT_NULL); + } + file_t user_fd (int fd) + { + if (fd < 0 || fd >= boot->dtablesize || + boot->dtable[fd] == MACH_PORT_NULL) + { + errno = EBADF; + return MACH_PORT_NULL; + } + return boot->dtable[fd]; + } + e.error = hurd_file_name_lookup (&user_port, &user_fd, 0, + name, O_READ, 0, &interp.file); + } + } + + if (interp.file != MACH_PORT_NULL) + { + /* We opened an interpreter file. Prepare it for loading too. */ + prepare_and_check (interp.file, &interp); + if (! interp.error) + { +#ifdef BFD + if (interp.bfd) + { + interp.info.bfd_locations = alloca (interp.bfd->section_count * + sizeof (vm_offset_t)); + bfd_map_over_sections (interp.bfd, check_section, &e); + } + else +#endif + { + const Elf32_Phdr *phdr = interp.info.elf.phdr; + interp.info.elf.phdr = alloca (interp.info.elf.phnum * + sizeof (Elf32_Phdr)); + check_elf_phdr (&interp, phdr, NULL, NULL); + } + } + e.error = interp.error; + } + + if (e.error) + goto out; + + + /* We are now committed to the exec. It "should not fail". + If it does fail now, the task will be hopelessly munged. */ + + if (newtask == oldtask) + { + thread_array_t threads; + mach_msg_type_number_t nthreads, i; + + /* Terminate all the threads of the old task. */ + + e.error = task_threads (oldtask, &threads, &nthreads); + if (e.error) + goto out; + for (i = 0; i < nthreads; ++i) + { + thread_terminate (threads[i]); + mach_port_deallocate (mach_task_self (), threads[i]); + } + munmap ((caddr_t) threads, nthreads * sizeof (thread_t)); + + /* Deallocate the entire virtual address space of the task. */ + + vm_deallocate (oldtask, + VM_MIN_ADDRESS, VM_MAX_ADDRESS - VM_MIN_ADDRESS); + + /* Nothing is supposed to go wrong any more. If anything does, the + old task is now in a hopeless state and must be killed. */ + oldtask_trashed = 1; + + /* Deallocate and destroy the ports requested by the caller. + These are ports the task wants not to lose if the exec call + fails, but wants removed from the new program task. */ + + for (i = 0; i < ndeallocnames; ++i) + mach_port_deallocate (oldtask, deallocnames[i]); + + for (i = 0; i < ndestroynames; ++i) + mach_port_destroy (oldtask, destroynames[i]); + } + +/* XXX this should be below + it is here to work around a vm_map kernel bug. */ + if (interp.file != MACH_PORT_NULL) + { + /* Load the interpreter file. */ + load (newtask, &interp); + if (interp.error) + { + e.error = interp.error; + goto out; + } + finish (&interp, 1); + } + + + /* Load the file into the task. */ + load (newtask, &e); + if (e.error) + goto out; + + /* XXX loading of interp belongs here */ + + /* Clean up. */ + finish (&e, 0); + + /* Now record some essential addresses from the image itself that the + program's startup code will need to know. We do this after loading + the image so that a load-anywhere image gets the adjusted addresses. */ +#ifdef BFD + if (!e.bfd) + phdr_addr += e.info.elf.loadbase; +#endif + boot->phdr_addr = phdr_addr; + boot->phdr_size = phdr_size; + boot->user_entry = e.entry; /* already adjusted in `load' */ + + /* Create the initial thread. */ + e.error = thread_create (newtask, &thread); + if (e.error) + goto out; + + /* Start up the initial thread at the entry point. */ + boot->stack_base = 0, boot->stack_size = 0; /* Don't care about values. */ + e.error = mach_setup_thread (newtask, thread, + (void *) (e.interp.section ? interp.entry : + e.entry), + &boot->stack_base, &boot->stack_size); + if (e.error) + goto out; + + if (oldtask != newtask && oldtask != MACH_PORT_NULL) + { + /* The program is on its way. The old task can be nuked. */ + process_t proc; + process_t psrv; + + /* Use the canonical proc server if secure, or there is none other. + When not secure, it is nice to let processes associate with + whatever proc server turns them on, regardless of which exec + itself is using. */ + if (secure + || boot->nports <= INIT_PORT_PROC + || boot->portarray[INIT_PORT_PROC] == MACH_PORT_NULL) + psrv = procserver; + else + psrv = boot->portarray[INIT_PORT_PROC]; + + /* XXX there is a race here for SIGKILLing the process. -roland + I don't think it matters. -mib */ + if (! proc_task2proc (psrv, oldtask, &proc)) + { + proc_reassign (proc, newtask); + mach_port_deallocate (mach_task_self (), proc); + } + + mach_port_deallocate (mach_task_self (), oldtask); + } + + /* Make sure the proc server has the right idea of our identity. */ + if (secure) + { + uid_t euidbuf[10], egidbuf[10], auidbuf[10], agidbuf[10]; + uid_t *euids, *egids, *auids, *agids; + size_t neuids, negids, nauids, nagids; + error_t err; + + /* Find out what our UID is from the auth server. */ + neuids = negids = nauids = nagids = 10; + euids = euidbuf, egids = egidbuf; + auids = auidbuf, agids = agidbuf; + err = auth_getids (boot->portarray[INIT_PORT_AUTH], + &euids, &neuids, &auids, &nauids, + &egids, &negids, &agids, &nagids); + + if (!err) + { + /* Set the owner with the proc server */ + /* Not much we can do about errors here; caller is responsible + for making sure that the provided proc port is correctly + authenticated anyhow. */ + proc_setowner (boot->portarray[INIT_PORT_PROC], + neuids ? euids[0] : 0, !neuids); + + /* Clean up */ + if (euids != euidbuf) + munmap (euids, neuids * sizeof (uid_t)); + if (egids != egidbuf) + munmap (egids, negids * sizeof (uid_t)); + if (auids != auidbuf) + munmap (auids, nauids * sizeof (uid_t)); + if (agids != agidbuf) + munmap (agids, nagids * sizeof (uid_t)); + } + } + + { + mach_port_t btport = ports_get_right (boot); + mach_port_insert_right (mach_task_self (), btport, btport, + MACH_MSG_TYPE_MAKE_SEND); + e.error = task_set_bootstrap_port (newtask, btport); + mach_port_deallocate (mach_task_self (), btport); + } + + out: + if (interp.file != MACH_PORT_NULL) + finish (&interp, 1); + finish (&e, !e.error); + + if (!e.error && (flags & EXEC_SIGTRAP)) /* XXX && !secure ? */ + { + /* This is a "traced" exec, i.e. the new task is to be debugged. The + caller has requested that the new process stop with SIGTRAP before + it starts. Since the process has no signal thread yet to do its + own POSIX signal mechanics, we simulate it by notifying the proc + server of the signal and leaving the initial thread with a suspend + count of one, as it would be if the process were stopped by a + POSIX signal. */ + mach_port_t proc; + if (boot->nports > INIT_PORT_PROC) + proc = boot->portarray[INIT_PORT_PROC]; + else + /* Ask the proc server for the proc port for this task. */ + e.error = proc_task2proc (procserver, newtask, &proc); + if (!e.error) + /* Tell the proc server that the process has stopped with the + SIGTRAP signal. Don't bother to check for errors from the RPC + here; for non-secure execs PROC may be the user's own proc + server its confusion shouldn't make the exec fail. */ + proc_mark_stop (proc, SIGTRAP, 0); + } + + if (boot) + { + /* Release the original reference. Now there is only one + reference, which will be released on no-senders notification. + If we are bailing out due to error before setting the task's + bootstrap port, this will be the last reference and BOOT + will get cleaned up here. */ + + if (e.error) + /* Kill the pointers to the argument information so the cleanup + of BOOT doesn't deallocate it. It will be deallocated my MiG + when we return the error. */ + bzero (&boot->pi + 1, (char *) &boot[1] - (char *) (&boot->pi + 1)); + else + /* Do this before we release the last reference. */ + if (boot->nports > INIT_PORT_PROC) + proc_mark_exec (boot->portarray[INIT_PORT_PROC]); + + ports_port_deref (boot); + } + + if (thread != MACH_PORT_NULL) + { + if (!e.error && !(flags & EXEC_SIGTRAP)) + thread_resume (thread); + mach_port_deallocate (mach_task_self (), thread); + } + + if (e.error) + { + if (oldtask != newtask) + { + /* We created a new task but failed to set it up. Kill it. */ + task_terminate (newtask); + mach_port_deallocate (mach_task_self (), newtask); + } + if (oldtask_trashed) + /* The old task is hopelessly trashed; there is no way it + can resume execution. Coup de grace. */ + task_terminate (oldtask); + else + /* Resume the old task, which we suspended earlier. */ + task_resume (oldtask); + } + else + { + if (oldtask != newtask) + { + /* We successfully set the new task up. + Terminate the old task and deallocate our right to it. */ + task_terminate (oldtask); + mach_port_deallocate (mach_task_self (), oldtask); + } + else + /* Resume the task, it is ready to run the new program. */ + task_resume (oldtask); + /* Deallocate the right to the new task we created. */ + mach_port_deallocate (mach_task_self (), newtask); + + for (i = 0; i < nports; ++i) + if (ports_replaced[i] && portarray[i] != MACH_PORT_NULL) + /* This port was replaced, so the reference that arrived in the + original portarray is not being saved in BOOT for transfer to + the user task. Deallocate it; we don't want it, and MiG will + leave it for us on successful return. */ + mach_port_deallocate (mach_task_self (), portarray[i]); + + /* If there is vm_allocate'd space for the original intarray and/or + portarray, and we are not saving those pointers in BOOT for later + transfer, deallocate the original space now. */ + if (intarray_dealloc) + munmap (intarray, nints * sizeof intarray[0]); + if (!portarray_copy) + munmap (portarray, nports * sizeof portarray[0]); + } + + return e.error; +} + +kern_return_t +S_exec_exec (struct trivfs_protid *protid, + file_t file, + task_t oldtask, + int flags, + char *argv, mach_msg_type_number_t argvlen, boolean_t argv_copy, + char *envp, mach_msg_type_number_t envplen, boolean_t envp_copy, + mach_port_t *dtable, mach_msg_type_number_t dtablesize, + boolean_t dtable_copy, + mach_port_t *portarray, mach_msg_type_number_t nports, + boolean_t portarray_copy, + int *intarray, mach_msg_type_number_t nints, + boolean_t intarray_copy, + mach_port_t *deallocnames, mach_msg_type_number_t ndeallocnames, + mach_port_t *destroynames, mach_msg_type_number_t ndestroynames) +{ + if (! protid) + return EOPNOTSUPP; + +#if 0 + if (!(flags & EXEC_SECURE)) + { + char *list = envz_get (envp, envplen, "EXECSERVERS"); + + if (list) + { + int tried = 0; + list = strdupa (list); + while ((p = strsep (&list, ":"))) + { + /* Open the named file using the appropriate directory ports for + the user. */ + error_t user_port (int which, error_t (*operate) (mach_port_t)) + { + return (*operate) (nports > which + ? portarray[which] : MACH_PORT_NULL); + } + file_t user_fd (int fd) + { + if (fd < 0 || fd >= dtablesize || + dtable[fd] == MACH_PORT_NULL) + { + errno = EBADF; + return MACH_PORT_NULL; + } + return dtable[fd]; + } + file_t server; + if (!hurd_file_name_lookup (user_port, user_fd, 0, p, 0,0, &server)) + { + error_t err; + struct trivfs_protid *protid + = ports_lookup_port (port_bucket, server, + trivfs_protid_portclasses[0]); + if (protid) + { + err = do_exec (file, oldtask, 0, + argv, argvlen, argv_copy, + envp, envplen, envp_copy, + dtable, dtablesize, dtable_copy, + portarray, nports, portarray_copy, + intarray, nints, intarray_copy, + deallocnames, ndeallocnames, + destroynames, ndestroynames); + ports_port_deref (protid); + } + else + { + int n; + err = exec_exec (server, + file, MACH_MSG_TYPE_COPY_SEND, + oldtask, 0, + argv, argvlen, + envp, envplen, + dtable, MACH_MSG_TYPE_COPY_SEND, + dtablesize, + portarray, MACH_MSG_TYPE_COPY_SEND, + nports, + intarray, nints, + deallocnames, ndeallocnames, + destroynames, ndestroynames); + mach_port_deallocate (mach_task_self (), file); + for (n = 0; n < dtablesize; n++) + mach_port_deallocate (mach_task_self (), dtable[n]); + for (n = 0; n < nports; n++) + mach_port_deallocate (mach_task_self (), portarray[n]); + } + mach_port_deallocate (mach_task_self (), server); + if (err != ENOEXEC) + return err; + tried = 1; + } + } + if (tried) + /* At least one exec server got a crack at it and gave up. */ + return ENOEXEC; + } + } +#endif + + /* There were no user-specified exec servers, + or none of them could be found. */ + + return do_exec (file, oldtask, flags, + argv, argvlen, argv_copy, + envp, envplen, envp_copy, + dtable, dtablesize, dtable_copy, + portarray, nports, portarray_copy, + intarray, nints, intarray_copy, + deallocnames, ndeallocnames, + destroynames, ndestroynames); +} + +kern_return_t +S_exec_setexecdata (struct trivfs_protid *protid, + mach_port_t *ports, mach_msg_type_number_t nports, int ports_copy, + int *ints, mach_msg_type_number_t nints, int ints_copy) +{ + error_t err; + + if (! protid || (protid->realnode != MACH_PORT_NULL && ! protid->isroot)) + return EPERM; + + if (nports < INIT_PORT_MAX || nints < INIT_INT_MAX) + return EINVAL; /* */ + + err = servercopy ((void **) &ports, nports * sizeof (mach_port_t), + ports_copy); + if (err) + return err; + err = servercopy ((void **) &ints, nints * sizeof (int), ints_copy); + if (err) + return err; + + rwlock_writer_lock (&std_lock); + + if (std_ports) + { + mach_msg_type_number_t i; + for (i = 0; i < std_nports; ++i) + mach_port_deallocate (mach_task_self (), std_ports[i]); + munmap (std_ports, std_nports * sizeof (mach_port_t)); + } + + std_ports = ports; + std_nports = nports; + + if (std_ints) + munmap (std_ints, std_nints * sizeof (int)); + + std_ints = ints; + std_nints = nints; + + rwlock_writer_unlock (&std_lock); + + return 0; +} + + +#include "exec_startup_S.h" + +/* RPC sent on the bootstrap port. */ + +kern_return_t +S_exec_startup_get_info (mach_port_t port, + vm_address_t *user_entry, + vm_address_t *phdr_data, vm_size_t *phdr_size, + vm_address_t *stack_base, vm_size_t *stack_size, + int *flags, + char **argvp, mach_msg_type_number_t *argvlen, + char **envpp, mach_msg_type_number_t *envplen, + mach_port_t **dtable, + mach_msg_type_name_t *dtablepoly, + mach_msg_type_number_t *dtablesize, + mach_port_t **portarray, + mach_msg_type_name_t *portpoly, + mach_msg_type_number_t *nports, + int **intarray, mach_msg_type_number_t *nints) +{ + struct bootinfo *boot = ports_lookup_port (port_bucket, port, + execboot_portclass); + if (! boot) + return EOPNOTSUPP; + ports_port_deref (boot); + + /* Pass back all the information we are storing. */ + + *user_entry = boot->user_entry; + *phdr_data = boot->phdr_addr; + *phdr_size = boot->phdr_size; + *stack_base = boot->stack_base; + *stack_size = boot->stack_size; + + *argvp = boot->argv; + *argvlen = boot->argvlen; + boot->argvlen = 0; + + *envpp = boot->envp; + *envplen = boot->envplen; + boot->envplen = 0; + + *dtable = boot->dtable; + *dtablesize = boot->dtablesize; + *dtablepoly = MACH_MSG_TYPE_MOVE_SEND; + boot->dtablesize = 0; + + *intarray = boot->intarray; + *nints = boot->nints; + boot->nints = 0; + + *portarray = boot->portarray; + *nports = boot->nports; + *portpoly = MACH_MSG_TYPE_MOVE_SEND; + boot->nports = 0; + + *flags = boot->flags; + + return 0; +} diff --git a/exec/execmutations.h b/exec/execmutations.h new file mode 100644 index 00000000..62ae5c55 --- /dev/null +++ b/exec/execmutations.h @@ -0,0 +1,6 @@ +/* CPP definitions for MiG processing of exec.defs for exec server. */ + +#define FILE_INTRAN trivfs_protid_t trivfs_begin_using_protid (file_t) +#define FILE_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t) + +#define EXEC_IMPORTS import "priv.h"; diff --git a/exec/exectrans.c b/exec/exectrans.c new file mode 100644 index 00000000..4c6e0cc0 --- /dev/null +++ b/exec/exectrans.c @@ -0,0 +1,79 @@ + +#include <stdio.h> +#include <getopt.h> +#include <error.h> +#include <sys/stat.h> + +#include <hurd.h> +#include <hurd/trivfs.h> + + +/* Where to put the service ports. */ +static struct port_bucket *port_bucket; + +/* Trivfs hooks. */ +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid = 0; +int trivfs_support_read = 1; +int trivfs_allow_open = O_READ; + +struct port_class *trivfs_protid_portclasses[1]; +struct port_class *trivfs_cntl_portclasses[1]; +int trivfs_protid_nportclasses = 1; +int trivfs_cntl_nportclasses = 1; + + +static int +exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) +{ + extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp); + return exec_server (inp, outp) || trivfs_demuxer (inp, outp); +} + +void +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) +{ + st->st_fstype = FSTYPE_MISC; +} + +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + int count; + + /* Stop new requests. */ + ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]); + ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]); + + /* Are there any extant user ports for the /servers/exec file? */ + count = ports_count_class (trivfs_protid_portclasses[0]); + if (count == 0 || (flags & FSYS_GOAWAY_FORCE)) + { + /* No users. Disconnect from the filesystem. */ + mach_port_deallocate (mach_task_self (), fsys->underlying); + + /* Are there remaining exec_startup RPCs to answer? */ + count = ports_count_class (execboot_portclass); + if (count == 0) + /* Nope. We got no reason to live. */ + exit (0); + + /* Continue servicing tasks starting up. */ + ports_enable_class (execboot_portclass); + + /* No more communication with the parent filesystem. */ + ports_destroy_right (fsys); + going_down = 1; + + return 0; + } + else + { + /* We won't go away, so start things going again... */ + ports_enable_class (trivfs_protid_portclasses[0]); + ports_resume_class_rpcs (trivfs_cntl_portclasses[0]); + ports_resume_class_rpcs (trivfs_protid_portclasses[0]); + + return EBUSY; + } +} diff --git a/exec/gcore.c b/exec/gcore.c new file mode 100644 index 00000000..7343516c --- /dev/null +++ b/exec/gcore.c @@ -0,0 +1,88 @@ +/* `gcore' for GNU Hurd. + Copyright (C) 1992 Free Software Foundation + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <hurd.h> +#include <hurd/core.h> +#include <limits.h> + +int +main (int argc, char **argv) +{ + file_t coreserv; + int i; + + if (argc < 2) + { + usage: + fprintf (stderr, "Usage: %s PID ...\n", program_invocation_short_name); + exit (1); + } + + coreserv = path_lookup (_SERVERS_CORE, 0, 0); + if (coreserv == MACH_PORT_NULL) + { + perror (_SERVERS_CORE); + exit (1); + } + + for (i = 1; i < argc; ++i) + { + char *end; + pid_t pid; + task_t task; + + pid = strtol (&argv[i], &end, 10); + if (end == &argv[i] || *end != '\0') + goto usage; + + task = pid2task ((pid_t) pid); + if (task == MACH_PORT_NULL) + fprintf (stderr, "pid2task: %d: %s\n", pid, strerror (errno)); + else + { + char name[PATH_MAX]; + file_t file; + sprintf (name, "core.%d", pid); + file = path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE, + 0666 &~ getumask ()); + if (file == MACH_PORT_NULL) + perror (name); + else + { + error_t err = core_dump_task (coreserv, task, + file, + 0, 0, + getenv ("GNUTARGET")); + mach_port_deallocate (mach_task_self (), file); + if (err) + { + (void) remove (name); + fprintf (stderr, "core_dump_task: %d: %s\n", + pid, strerror (err)); + } + } + } + mach_port_deallocate (mach_task_self (), task); + } + + exit (0); +} diff --git a/exec/gzip.h b/exec/gzip.h new file mode 100644 index 00000000..aedc257d --- /dev/null +++ b/exec/gzip.h @@ -0,0 +1,315 @@ +/* gzip.h -- common declarations for all gzip modules + * Copyright (C) 1992-1993, 1996 Jean-loup Gailly. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +#if defined(__STDC__) || defined(PROTO) +# define OF(args) args +#else +# define OF(args) () +#endif + +#ifdef __STDC__ + typedef void *voidp; +#else + typedef char *voidp; +#endif + +/* I don't like nested includes, but the string and io functions are used + * too often + */ +#include <stdio.h> +#if !defined(NO_STRING_H) || defined(STDC_HEADERS) +# include <string.h> +# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__) +# include <memory.h> +# endif +# define memzero(s, n) memset ((voidp)(s), 0, (n)) +#else +# include <strings.h> +# define strchr index +# define strrchr rindex +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) +# define memzero(s, n) bzero((s), (n)) +#endif + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#define local static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* Return codes from gzip */ +#define OK 0 +#define ERROR 1 +#define WARNING 2 + +/* Compression methods (see algorithm.doc) */ +#define STORED 0 +#define COMPRESSED 1 +#define PACKED 2 +#define LZHED 3 +/* methods 4 to 7 reserved */ +#define DEFLATED 8 +#define MAX_METHODS 9 +extern int method; /* compression method */ + +/* To save memory for 16 bit systems, some arrays are overlaid between + * the various modules: + * deflate: prev+head window d_buf l_buf outbuf + * unlzw: tab_prefix tab_suffix stack inbuf outbuf + * inflate: window inbuf + * unpack: window inbuf prefix_len + * unlzh: left+right window c_table inbuf c_len + * For compression, input is done in window[]. For decompression, output + * is done in window except for unlzw. + */ + +#ifndef INBUFSIZ +# ifdef SMALL_MEM +# define INBUFSIZ 0x2000 /* input buffer size */ +# else +# define INBUFSIZ 0x8000 /* input buffer size */ +# endif +#endif +#define INBUF_EXTRA 64 /* required by unlzw() */ + +#ifndef OUTBUFSIZ +# ifdef SMALL_MEM +# define OUTBUFSIZ 8192 /* output buffer size */ +# else +# define OUTBUFSIZ 16384 /* output buffer size */ +# endif +#endif +#define OUTBUF_EXTRA 2048 /* required by unlzw() */ + +#ifndef DIST_BUFSIZE +# ifdef SMALL_MEM +# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */ +# else +# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ +# endif +#endif + +#ifdef DYN_ALLOC +# define EXTERN(type, array) extern type * near array +# define DECLARE(type, array, size) type * near array +# define ALLOC(type, array, size) { \ + array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ + if (array == NULL) error("insufficient memory"); \ + } +# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} +#else +# define EXTERN(type, array) extern type array[] +# define DECLARE(type, array, size) type array[size] +# define ALLOC(type, array, size) +# define FREE(array) +#endif + +EXTERN(uch, inbuf); /* input buffer */ +EXTERN(uch, outbuf); /* output buffer */ +EXTERN(ush, d_buf); /* buffer for distances, see trees.c */ +EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */ +#define tab_suffix window +#ifndef MAXSEG_64K +# define tab_prefix prev /* hash link (see deflate.c) */ +# define head (prev+WSIZE) /* hash head (see deflate.c) */ + EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */ +#else +# define tab_prefix0 prev +# define head tab_prefix1 + EXTERN(ush, tab_prefix0); /* prefix for even codes */ + EXTERN(ush, tab_prefix1); /* prefix for odd codes */ +#endif + +extern unsigned insize; /* valid bytes in inbuf */ +extern unsigned inptr; /* index of next byte to be processed in inbuf */ +extern unsigned outcnt; /* bytes in output buffer */ + +extern long bytes_in; /* number of input bytes */ +extern long bytes_out; /* number of output bytes */ +extern long header_bytes;/* number of bytes in gzip header */ + +#define isize bytes_in +/* for compatibility with old zip sources (to be cleaned) */ + +extern int ifd; /* input file descriptor */ +extern int ofd; /* output file descriptor */ +extern char ifname[]; /* input file name or "stdin" */ +extern char ofname[]; /* output file name or "stdout" */ +extern char *progname; /* program name */ + +extern long time_stamp; /* original time stamp (modification time) */ +extern long ifile_size; /* input file size, -1 for devices (debug only) */ + +typedef int file_t; /* Do not use stdio */ +#define NO_FILE (-1) /* in memory compression */ + + +#define PACK_MAGIC "\037\036" /* Magic header for packed files */ +#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ +#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ +#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/ +#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* internal file attribute */ +#define UNKNOWN 0xffff +#define BINARY 0 +#define ASCII 1 + +#ifndef WSIZE +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +#endif /* at least 32K for zip's deflate method */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +extern int decrypt; /* flag to turn on decryption */ +extern int exit_code; /* program exit code */ +extern int verbose; /* be verbose (-v) */ +extern int quiet; /* be quiet (-q) */ +extern int level; /* compression level */ +extern int test; /* check .z file integrity */ +extern int to_stdout; /* output to stdout (-c) */ +extern int save_orig_name; /* set if original name must be saved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0)) +#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1)) + +/* put_byte is used for the compressed output, put_ubyte for the + * uncompressed output. However unlzw() uses window for its + * suffix table instead of its output buffer, so it does not use put_ubyte + * (to be cleaned up). + */ +#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ + flush_outbuf();} +#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\ + flush_window();} + +/* Output a 16 bit value, lsb first */ +#define put_short(w) \ +{ if (outcnt < OUTBUFSIZ-2) { \ + outbuf[outcnt++] = (uch) ((w) & 0xff); \ + outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ + } else { \ + put_byte((uch)((w) & 0xff)); \ + put_byte((uch)((ush)(w) >> 8)); \ + } \ +} + +/* Output a 32 bit value to the bit stream, lsb first */ +#define put_long(n) { \ + put_short((n) & 0xffff); \ + put_short(((ulg)(n)) >> 16); \ +} + +#define seekable() 0 /* force sequential output */ +#define translate_eol 0 /* no option -a yet */ + +#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */ + +/* Macros for getting two-byte and four-byte header values */ +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#define WARN(msg) {if (!quiet) fprintf msg ; \ + if (exit_code == OK) exit_code = WARNING;} + + /* in zip.c: */ +extern int zip OF((int in, int out)); +extern int file_read OF((char *buf, unsigned size)); + + /* in unzip.c */ +extern int unzip OF((int in, int out)); +extern int check_zipfile OF((int in)); + + /* in unpack.c */ +extern int unpack OF((int in, int out)); + + /* in unlzh.c */ +extern int unlzh OF((int in, int out)); + + /* in gzip.c */ +RETSIGTYPE abort_gzip OF((void)); + + /* in deflate.c */ +void lm_init OF((int pack_level, ush *flags)); +ulg deflate OF((void)); + + /* in trees.c */ +void ct_init OF((ush *attr, int *method)); +int ct_tally OF((int dist, int lc)); +ulg flush_block OF((char *buf, ulg stored_len, int eof)); + + /* in bits.c */ +void bi_init OF((file_t zipfile)); +void send_bits OF((int value, int length)); +unsigned bi_reverse OF((unsigned value, int length)); +void bi_windup OF((void)); +void copy_block OF((char *buf, unsigned len, int header)); +extern int (*read_buf) OF((char *buf, unsigned size)); + + /* in util.c: */ +extern int copy OF((int in, int out)); +extern ulg updcrc OF((uch *s, unsigned n)); +extern void clear_bufs OF((void)); +extern int fill_inbuf OF((int eof_ok)); +extern void flush_outbuf OF((void)); +extern void flush_window OF((void)); +extern void write_buf OF((int fd, voidp buf, unsigned cnt)); +extern char *strlwr OF((char *s)); +/* extern char *basename OF((char *fname));*/ +extern void make_simple_name OF((char *name)); +extern char *add_envopt OF((int *argcp, char ***argvp, char *env)); +extern void error OF((char *m)); +extern void warn OF((char *a, char *b)); +extern void read_error OF((void)); +extern void write_error OF((void)); +extern void display_ratio OF((long num, long den, FILE *file)); +extern voidp xmalloc OF((unsigned int size)); + + /* in inflate.c */ +extern int inflate OF((void)); diff --git a/exec/hashexec.c b/exec/hashexec.c new file mode 100644 index 00000000..03981da4 --- /dev/null +++ b/exec/hashexec.c @@ -0,0 +1,429 @@ +/* GNU Hurd standard exec server, #! script execution support. + Copyright (C) 1995, 96, 97, 98, 99 Free Software Foundation, Inc. + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "priv.h" +#include <hurd/sigpreempt.h> +#include <unistd.h> +#include <envz.h> + +/* This is called to check E for a #! interpreter specification. E has + already been prepared (successfully) and checked (unsuccessfully). If + we return success, our caller just returns success for the RPC; we must + handle all the RPC argument details ourselves. If we return ENOEXEC, we + should leave everything as it was. If we return failure other than + ENOEXEC, our caller will just fail the RPC. */ +void +check_hashbang (struct execdata *e, + file_t file, + task_t oldtask, + int flags, + char *argv, u_int argvlen, boolean_t argv_copy, + char *envp, u_int envplen, boolean_t envp_copy, + mach_port_t *dtable, u_int dtablesize, boolean_t dtable_copy, + mach_port_t *portarray, u_int nports, boolean_t portarray_copy, + int *intarray, u_int nints, boolean_t intarray_copy, + mach_port_t *deallocnames, u_int ndeallocnames, + mach_port_t *destroynames, u_int ndestroynames) +{ + char *ibuf = NULL; + size_t ibufsiz = 0; + char *p; + char *interp, *arg; /* Interpreter file name, and first argument */ + size_t interp_len, len; + file_t interp_file; /* Port open on the interpreter file. */ + FILE *f = &e->stream; + char *new_argv; + size_t new_argvlen; + mach_port_t *new_dtable = NULL; + u_int new_dtablesize; + + file_t user_fd (int fd) + { + if (fd < 0 || fd >= dtablesize || dtable[fd] == MACH_PORT_NULL) + { + errno = EBADF; + return MACH_PORT_NULL; + } + return dtable[fd]; + } + file_t user_crdir, user_cwdir; + error_t user_port (int which, error_t (*operate) (mach_port_t)) + { + error_t reauthenticate (file_t unauth, file_t *result) + { + error_t err; + mach_port_t ref; + error_t uauth (auth_t auth) + { + return auth_user_authenticate (auth, + ref, MACH_MSG_TYPE_MAKE_SEND, + result); + } + if (*result != MACH_PORT_NULL) + return 0; + ref = mach_reply_port (); + err = io_reauthenticate (unauth, ref, MACH_MSG_TYPE_MAKE_SEND); + if (!err) + err = user_port (INIT_PORT_AUTH, &uauth); + mach_port_destroy (mach_task_self (), ref); + return err; + } + + /* Find the specified port, using defaults if so specified. */ + mach_port_t port = ((which < nports && + portarray[which] != MACH_PORT_NULL) + ? portarray[which] : + (flags & EXEC_DEFAULTS) ? std_ports[which] + : MACH_PORT_NULL); + + /* Reauthenticate dir ports if they are the defaults. */ + switch (which) + { + case INIT_PORT_CRDIR: + /* If secure, always use the default root. */ + if ((flags & EXEC_SECURE) || + port == std_ports[which]) + return (reauthenticate (std_ports[which], &user_crdir) ?: + (*operate) (user_crdir)); + break; + case INIT_PORT_CWDIR: + /* If secure, reauthenticate cwd whether default or given. */ + if ((flags & EXEC_SECURE) || port == std_ports[which]) + return (reauthenticate (port, &user_cwdir) ?: + (*operate) (user_cwdir)); + break; + } + + return (*operate) (port); + } + /* Look up NAME on behalf of the client. */ + inline error_t lookup (const char *name, int flags, mach_port_t *result) + { + return hurd_file_name_lookup (&user_port, &user_fd, 0, + name, flags, 0, result); + } + + rewind (f); + + /* Check for our ``magic number''--"#!". */ + + errno = 0; + if (getc (f) != '#' || getc (f) != '!') + { + /* No `#!' here. If there was a read error (not including EOF), + return that error indication. Otherwise return ENOEXEC to + say it's not a file we know how to execute. */ + e->error = ferror (f) ? errno : ENOEXEC; + return; + } + + /* Read the rest of the first line of the file. */ + + interp_len = getline (&ibuf, &ibufsiz, f); + if (ferror (f)) + { + e->error = errno ?: EIO; + return; + } + if (ibuf[interp_len - 1] == '\n') + ibuf[--interp_len] = '\0'; + + /* Find the name of the interpreter. */ + p = ibuf + strspn (ibuf, " \t"); + interp = strsep (&p, " \t"); + + if (p) + { + /* Skip remaining blanks, and the rest of the line is the argument. */ + p += strspn (p, " \t"); + arg = p; + len = interp_len - (arg - ibuf); + + if (len == 0) + arg = NULL; + else + { + /* Trim trailing blanks after the argument. */ + size_t i = len - 1; + while (arg[i] == ' ' || arg[i] == '\t') + arg[i--] = '\0'; + len = i + 2; /* Include the terminating null. */ + } + } + else + { + /* There is no argument. */ + arg = NULL; + len = 0; + } + + interp_len = strlen (interp) + 1; + + user_crdir = user_cwdir = MACH_PORT_NULL; + + rwlock_reader_lock (&std_lock); + + /* Open a port on the interpreter file. */ + e->error = lookup (interp, O_EXEC, &interp_file); + + if (! e->error) + { + int free_file_name = 0; /* True if we should free FILE_NAME. */ + jmp_buf args_faulted; + void fault_handler (int signo) + { longjmp (args_faulted, 1); } + error_t setup_args (struct hurd_signal_preemptor *preemptor) + { + size_t namelen; + char * volatile file_name = NULL; + + if (setjmp (args_faulted)) + file_name = NULL; + else if (! (flags & EXEC_SECURE)) + { + /* Try to figure out the file's name. We guess that if ARGV[0] + contains a slash, it might be the name of the file; and that + if it contains no slash, looking for files named by ARGV[0] in + the `PATH' environment variable might find it. */ + + error_t error; + char *name; + int free_name = 0; /* True if we should free NAME. */ + file_t name_file; + mach_port_t fileid; + dev_t filedev; + ino_t fileno; + + /* Search $PATH for NAME, opening a port NAME_FILE on it. + This is encapsulated in a function so we can catch faults + reading the user's environment. */ + error_t search_path (struct hurd_signal_preemptor *preemptor) + { + error_t err; + char *path = envz_get (envp, envplen, "PATH"), *pfxed_name; + + if (! path) + { + const size_t len = confstr (_CS_PATH, NULL, 0); + path = alloca (len); + confstr (_CS_PATH, path, len); + } + + err = hurd_file_name_path_lookup (user_port, user_fd, 0, + name, path, O_EXEC, 0, + &name_file, &pfxed_name); + if (!err && pfxed_name) + { + name = pfxed_name; + free_name = 1; + } + + return err; + } + + error = io_identity (file, &fileid, &filedev, &fileno); + if (error) + goto out; + + if (memchr (argv, '\0', argvlen) == NULL) + { + name = alloca (argvlen + 1); + bcopy (argv, name, argvlen); + name[argvlen] = '\0'; + } + else + name = argv; + + if (strchr (name, '/') != NULL) + error = lookup (name, 0, &name_file); + else if ((error = hurd_catch_signal + (sigmask (SIGBUS) | sigmask (SIGSEGV), + (vm_address_t) envp, (vm_address_t) envp + envplen, + &search_path, SIG_ERR))) + name_file = MACH_PORT_NULL; + + if (!error && name_file != MACH_PORT_NULL) + { + mach_port_t id; + dev_t dev; + ino_t ino; + error = io_identity (name_file, &id, &dev, &ino); + mach_port_deallocate (mach_task_self (), id); + if (!error && id == fileid) + { + file_name = name; + free_file_name = free_name; + } + else if (free_name) + free (name); + mach_port_deallocate (mach_task_self (), name_file); + } + + mach_port_deallocate (mach_task_self (), fileid); + } + + if (file_name == NULL) + { + /* We can't easily find the file. + Put it in a file descriptor and pass /dev/fd/N. */ + int fd; + out: + + for (fd = 0; fd < dtablesize; ++fd) + if (dtable[fd] == MACH_PORT_NULL) + break; + if (fd == dtablesize) + { + /* Extend the descriptor table. */ + new_dtable = alloca ((dtablesize + 1) * sizeof (file_t)); + memcpy (new_dtable, dtable, dtablesize * sizeof (file_t)); + new_dtablesize = dtablesize + 1; + new_dtable[fd] = file; + } + else + dtable[fd] = file; + mach_port_mod_refs (mach_task_self (), file, + MACH_PORT_RIGHT_SEND, +1); + + file_name = alloca (100); + sprintf (file_name, "/dev/fd/%d", fd); + } + + /* Prepare the arguments to pass to the interpreter from the original + arguments and the name of the script file. The args will look + like `INTERP {ARG} FILE_NAME ARGV[1..n]' (ARG might have been + omitted). */ + + namelen = strlen (file_name) + 1; + + new_argvlen + = (argvlen - strlen (argv) - 1) /* existing args - old argv[0] */ + + interp_len + len + namelen; /* New args */ + + new_argv = mmap (0, new_argvlen, PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (new_argv == (caddr_t) -1) + { + e->error = errno; + return e->error; + } + else + e->error = 0; + + if (! setjmp (args_faulted)) + { + char *other_args; + + p = new_argv; + + /* INTERP */ + memcpy (p, interp, interp_len); + p += interp_len; + + /* Maybe ARG */ + if (arg) + { + memcpy (p, arg, len); + p += len; + } + + /* FILE_NAME */ + memcpy (p, file_name, namelen); + p += namelen; + + /* Maybe remaining args */ + other_args = argv + strlen (argv) + 1; + if (other_args - argv < argvlen) + memcpy (p, other_args, argvlen - (other_args - argv)); + } + else + { + /* We got a fault reading ARGV. So don't use it. */ + char *n = stpncpy (new_argv, + "**fault in exec server reading argv[0]**", + argvlen); + memcpy (memcpy (n, arg, len) + len, file_name, namelen); + } + + if (free_file_name) + free (file_name); + + return 0; + } + + /* Set up the arguments. */ + hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS), + (vm_address_t) argv, (vm_address_t) argv + argvlen, + &setup_args, &fault_handler); + } + + /* We are now done reading the script file. */ + finish (e, 0); + free (ibuf); + + rwlock_reader_unlock (&std_lock); + + if (user_crdir != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), user_crdir); + if (user_cwdir != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), user_cwdir); + + if (e->error) + /* We cannot open the interpreter file to execute it. Lose! */ + return; + + /* Execute the interpreter program. */ + e->error = file_exec (interp_file, + oldtask, flags, + new_argv, new_argvlen, envp, envplen, + new_dtable ?: dtable, MACH_MSG_TYPE_COPY_SEND, + new_dtable ? new_dtablesize : dtablesize, + portarray, MACH_MSG_TYPE_COPY_SEND, nports, + intarray, nints, + deallocnames, ndeallocnames, + destroynames, ndestroynames); + mach_port_deallocate (mach_task_self (), interp_file); + + if (! e->error) + { + /* The exec of the interpreter succeeded! Deallocate the resources + we passed to that exec. We don't need to save them in a bootinfo + structure; the exec of the interpreter takes care of that. */ + u_int i; + mach_port_deallocate (mach_task_self (), file); + task_resume (oldtask); /* Our caller suspended it. */ + mach_port_deallocate (mach_task_self (), oldtask); + if (! argv_copy) + munmap (argv, argvlen); + if (! envp_copy) + munmap (envp, envplen); + for (i = 0; i < dtablesize; ++i) + mach_port_deallocate (mach_task_self (), dtable[i]); + if (! dtable_copy) + munmap (dtable, dtablesize * sizeof *dtable); + for (i = 0; i < nports; ++i) + mach_port_deallocate (mach_task_self (), portarray[i]); + if (! portarray_copy) + munmap (portarray, nports * sizeof *portarray); + if (! intarray_copy) + munmap (intarray, nints * sizeof *intarray); + } +} diff --git a/exec/hostarch.c b/exec/hostarch.c new file mode 100644 index 00000000..e62e666f --- /dev/null +++ b/exec/hostarch.c @@ -0,0 +1,187 @@ +/* Determine the BFD and ELF architecture and machine flavor + from a Mach host port. Used by the exec and core servers. + Copyright (C) 1992, 1993, 1995, 1996, 1999 Free Software Foundation, Inc. + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "priv.h" +#include <mach.h> +#include <hurd/hurd_types.h> +#include <errno.h> +#include <elf.h> + +error_t +elf_machine_matches_host (Elf32_Half e_machine) +{ + static void *host_type; /* Cached entry into the switch below. */ + struct host_basic_info hostinfo; + + if (host_type) + goto *host_type; + else + { + error_t err; + mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; + + err = host_info (mach_host_self (), HOST_BASIC_INFO, + (natural_t *) &hostinfo, &hostinfocnt); + if (err) + return err; + assert (hostinfocnt == HOST_BASIC_INFO_COUNT); + } + +#define CACHE(test) ({ __label__ here; host_type = &&here; \ + here: return (test) ? 0 : ENOEXEC; }) + switch (hostinfo.cpu_type) + { + case CPU_TYPE_MC68020: + case CPU_TYPE_MC68030: + case CPU_TYPE_MC68040: + CACHE (e_machine == EM_68K); + + case CPU_TYPE_I860: + CACHE (e_machine == EM_860); + + case CPU_TYPE_MIPS: + CACHE (e_machine == EM_MIPS); + + case CPU_TYPE_MC88000: + CACHE (e_machine == EM_88K); + + case CPU_TYPE_SPARC: + CACHE (e_machine == EM_SPARC); + + case CPU_TYPE_I386: + CACHE (e_machine == EM_386); + case CPU_TYPE_I486: + case CPU_TYPE_PENTIUM: + case CPU_TYPE_PENTIUMPRO: + CACHE (e_machine == EM_386 || e_machine == EM_486); + + case CPU_TYPE_POWERPC: + CACHE (e_machine == EM_PPC); + + case CPU_TYPE_ALPHA: + CACHE (e_machine == EM_ALPHA); + + case CPU_TYPE_HPPA: + CACHE (e_machine == EM_PARISC); + + default: + return EGRATUITOUS; /* XXX */ + } + + return 0; +} + +#ifdef BFD +#include <bfd.h> + +error_t +bfd_mach_host_arch_mach (host_t host, + enum bfd_architecture *arch, + long int *machine) +{ + error_t err; + struct host_basic_info hostinfo; + mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; + + err = host_info (host, HOST_BASIC_INFO, (natural_t *) &hostinfo, &hostinfocnt); + if (err) + return err; + + *machine = hostinfo.cpu_subtype; + *e_machine = EM_NONE; + switch (hostinfo.cpu_type) + { + case CPU_TYPE_MC68020: + *arch = bfd_arch_m68k; + *machine = 68020; + *e_machine = EM_68K; + break; + case CPU_TYPE_MC68030: + *arch = bfd_arch_m68k; + *machine = 68030; + *e_machine = EM_68K; + break; + case CPU_TYPE_MC68040: + *arch = bfd_arch_m68k; + *machine = 68040; + *e_machine = EM_68K; + break; + + case CPU_TYPE_NS32032: + *arch = bfd_arch_ns32k; + *machine = 32032; + break; + case CPU_TYPE_NS32332: + *arch = bfd_arch_ns32k; + *machine = 32332; + break; + case CPU_TYPE_NS32532: + *arch = bfd_arch_ns32k; + *machine = 32532; + break; + + case CPU_TYPE_ROMP: + *arch = bfd_arch_romp; + break; + + case CPU_TYPE_I860: + *arch = bfd_arch_i860; + *e_machine = EM_860; + break; + + case CPU_TYPE_MIPS: + *arch = bfd_arch_mips; + *e_machine = EM_MIPS; + break; + + case CPU_TYPE_VAX: + *arch = bfd_arch_vax; + break; + + case CPU_TYPE_MC88000: + *arch = bfd_arch_m88k; + *e_machine = EM_88K; + break; + + case CPU_TYPE_SPARC: + *arch = bfd_arch_sparc; + *e_machine = EM_SPARC; + break; + + case CPU_TYPE_I386: + *arch = bfd_arch_i386; + *e_machine = EM_386; + break; + +#ifdef CPU_TYPE_ALPHA + case CPU_TYPE_ALPHA: + *arch = bfd_arch_alpha; + break; +#endif + + default: + return ENOEXEC; + } + + return 0; +} + +#endif /* BFD */ diff --git a/exec/inflate.c b/exec/inflate.c new file mode 100644 index 00000000..c3be4381 --- /dev/null +++ b/exec/inflate.c @@ -0,0 +1,954 @@ +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* You can do whatever you like with this source file, though I would + prefer that if you modify it and redistribute it that you include + comments to that effect with your name and the date. Thank you. + [The history has been moved to the file ChangeLog.] + */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32K or 64K. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a mutli-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + +#ifdef RCSID +static char rcsid[] = "$Id: inflate.c,v 1.1 1994/12/14 04:31:21 roland Exp $"; +#endif + +#include <sys/types.h> + +#include "tailor.h" + +#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H) +# include <stdlib.h> +#endif + +#include "gzip.h" +#define slide window + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *)); +int huft_free OF((struct huft *)); +int inflate_codes OF((struct huft *, struct huft *, int, int)); +int inflate_stored OF((void)); +int inflate_fixed OF((void)); +int inflate_dynamic OF((void)); +int inflate_block OF((int *)); +int inflate OF((void)); + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ +/* unsigned wp; current position in slide */ +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ + +ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#ifdef CRYPT + uch cc; +# define NEXTBYTE() \ + (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) +#else +# define NEXTBYTE() (uch)get_byte() +#endif +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}} +#define DUMPBITS(n) {b>>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +int lbits = 9; /* bits in base literal/length lookup table */ +int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +unsigned hufts; /* track memory usage */ + + +int huft_build(b, n, s, d, e, t, m) +unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ +unsigned n; /* number of codes (assumed <= N_MAX) */ +unsigned s; /* number of simple-valued codes (0..s-1) */ +ush *d; /* list of base values for non-simple codes */ +ush *e; /* list of extra bits for non-simple codes */ +struct huft **t; /* result: starting table */ +int *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), + n-i, *p)); + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)(*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free((char*)p); + p = q; + } + return 0; +} + + +int inflate_codes(tl, td, bl, bd) +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + Tracevv((stderr, "%c", slide[w-1])); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + Tracevv((stderr,"\\[%d,%d]", w-d, n)); + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + Tracevv((stderr, "%c", slide[w-1])); + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +int inflate_stored() +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + slide[w++] = (uch)b; + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + return 0; +} + + + +int inflate_fixed() +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) + return i; + + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) + { + huft_free(tl); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +int inflate_dynamic() +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) +#ifdef PKZIP_BUG_WORKAROUND + if (nl > 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + + /* free decoding table for trees */ + huft_free(tl); + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { + if (i == 1) { + fprintf(stderr, " incomplete literal tree\n"); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { + if (i == 1) { + fprintf(stderr, " incomplete distance tree\n"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +int inflate_block(e) +int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(); + if (t == 0) + return inflate_stored(); + if (t == 1) + return inflate_fixed(); + + + /* bad block type */ + return 2; +} + + + +int inflate() +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) + return r; + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + inptr--; + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ +#ifdef DEBUG + fprintf(stderr, "<%u> ", h); +#endif /* DEBUG */ + return 0; +} diff --git a/exec/main.c b/exec/main.c new file mode 100644 index 00000000..033f7f0f --- /dev/null +++ b/exec/main.c @@ -0,0 +1,259 @@ +/* GNU Hurd standard exec server, main program and server mechanics. + + Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. + Written by Roland McGrath. + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "priv.h" +#include <error.h> +#include <hurd/paths.h> +#include <hurd/startup.h> +#include <argp.h> +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (proc); + +#ifdef BFD +bfd_arch_info_type host_bfd_arch_info; +bfd host_bfd = { arch_info: &host_bfd_arch_info }; +extern error_t bfd_mach_host_arch_mach (host_t host, + enum bfd_architecture *bfd_arch, + long int *bfd_machine, + Elf32_Half *elf_machine); +#endif + +/* Trivfs hooks. */ +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid = 0; +int trivfs_support_read = 1; +int trivfs_support_write = 1; +int trivfs_support_exec = 1; +int trivfs_allow_open = O_READ|O_WRITE|O_EXEC; + +struct port_class *trivfs_protid_portclasses[1]; +struct port_class *trivfs_cntl_portclasses[1]; +int trivfs_protid_nportclasses = 1; +int trivfs_cntl_nportclasses = 1; + +struct trivfs_control *fsys; + +char **save_argv; + + +static int +exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) +{ + extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp); + extern int exec_startup_server (mach_msg_header_t *, mach_msg_header_t *); + return (exec_startup_server (inp, outp) || + exec_server (inp, outp) || + trivfs_demuxer (inp, outp)); +} + + +/* Clean up the storage in BOOT, which was never used. */ + +void +deadboot (void *p) +{ + struct bootinfo *boot = p; + size_t i; + + munmap (boot->argv, boot->argvlen); + munmap (boot->envp, boot->envplen); + + for (i = 0; i < boot->dtablesize; ++i) + mach_port_deallocate (mach_task_self (), boot->dtable[i]); + for (i = 0; i < boot->nports; ++i) + mach_port_deallocate (mach_task_self (), boot->portarray[i]); + munmap (boot->portarray, boot->nports * sizeof (mach_port_t)); + munmap (boot->intarray, boot->nints * sizeof (int)); + + /* See if we are going away and this was the last thing keeping us up. */ + if (ports_count_class (trivfs_cntl_portclasses[0]) == 0) + { + /* We have no fsys control port, so we are detached from the + parent filesystem. Maybe we have no users left either. */ + if (ports_count_class (trivfs_protid_portclasses[0]) == 0) + { + /* We have no user ports left. Are we still listening for + exec_startup RPCs from any tasks we already started? */ + if (ports_count_class (execboot_portclass) == 0) + /* Nobody talking. Time to die. */ + exit (0); + ports_enable_class (execboot_portclass); + } + ports_enable_class (trivfs_protid_portclasses[0]); + } + ports_enable_class (trivfs_cntl_portclasses[0]); +} + + +int +main (int argc, char **argv) +{ + error_t err; + mach_port_t bootstrap; + struct argp argp = { 0, 0, 0, "Hurd standard exec server" }; + + argp_parse (&argp, argc, argv, 0, 0, 0); + + save_argv = argv; + +#ifdef BFD + /* Put the Mach kernel's idea of what flavor of machine this is into the + fake BFD against which architecture compatibility checks are made. */ + err = bfd_mach_host_arch_mach (mach_host_self (), + &host_bfd.arch_info->arch, + &host_bfd.arch_info->mach); + if (err) + error (1, err, "Getting host architecture from Mach"); +#endif + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (2, 0, "Must be started as a translator"); + + /* Fetch our proc server port for easy use. If we are booting, it is not + set yet and `getproc' returns MACH_PORT_NULL; we reset PROCSERVER in + S_exec_init (below). */ + procserver = getproc (); + + port_bucket = ports_create_bucket (); + trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0); + trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0); + execboot_portclass = ports_create_class (deadboot, NULL); + + /* Reply to our parent. */ + err = trivfs_startup (bootstrap, 0, + trivfs_cntl_portclasses[0], port_bucket, + trivfs_protid_portclasses[0], port_bucket, + &fsys); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + error (3, err, "Contacting parent"); + + /* Launch. */ + ports_manage_port_operations_multithread (port_bucket, exec_demuxer, + 2 * 60 * 1000, 0, 0); + + return 0; +} + + +void +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) +{ + st->st_fstype = FSTYPE_MISC; +} + +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + int count; + + /* Stop new requests. */ + ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]); + ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]); + + /* Are there any extant user ports for the /servers/exec file? */ + count = ports_count_class (trivfs_protid_portclasses[0]); + if (count == 0 || (flags & FSYS_GOAWAY_FORCE)) + { + /* No users. Disconnect from the filesystem. */ + mach_port_deallocate (mach_task_self (), fsys->underlying); + + /* Are there remaining exec_startup RPCs to answer? */ + count = ports_count_class (execboot_portclass); + if (count == 0) + /* Nope. We got no reason to live. */ + exit (0); + + /* Continue servicing tasks starting up. */ + ports_enable_class (execboot_portclass); + + /* No more communication with the parent filesystem. */ + ports_destroy_right (fsys); + + return 0; + } + else + { + /* We won't go away, so start things going again... */ + ports_enable_class (trivfs_protid_portclasses[0]); + ports_resume_class_rpcs (trivfs_cntl_portclasses[0]); + ports_resume_class_rpcs (trivfs_protid_portclasses[0]); + + return EBUSY; + } +} + +/* Sent by the bootstrap filesystem after the other essential + servers have been started up. */ + +kern_return_t +S_exec_init (struct trivfs_protid *protid, + auth_t auth, process_t proc) +{ + mach_port_t host_priv, startup; + error_t err; + + if (! protid || ! protid->isroot) + return EPERM; + + _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc); /* Consume. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], auth); /* Consume. */ + + /* Do initial setup with the proc server. */ + _hurd_proc_init (save_argv, NULL, 0); + + procserver = getproc (); + + /* Have the proc server notify us when the canonical ints and ports + change. This will generate an immediate callback giving us the + initial boot-time canonical sets. */ + { + struct trivfs_protid *cred; + err = trivfs_open (fsys, + iohelp_create_iouser (make_idvec (), make_idvec ()), + 0, MACH_PORT_NULL, &cred); + assert_perror (err); + + proc_execdata_notify (procserver, ports_get_right (cred), + MACH_MSG_TYPE_MAKE_SEND); + } + + err = get_privileged_ports (&host_priv, NULL); + assert_perror (err); + + proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION); + + err = proc_getmsgport (procserver, 1, &startup); + assert_perror (err); + mach_port_deallocate (mach_task_self (), procserver); + + /* Call startup_essential task last; init assumes we are ready to + run once we call it. */ + err = startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, + "exec", host_priv); + assert_perror (err); + mach_port_deallocate (mach_task_self (), startup); + + mach_port_deallocate (mach_task_self (), host_priv); + + return 0; +} diff --git a/exec/priv.h b/exec/priv.h new file mode 100644 index 00000000..f6889b32 --- /dev/null +++ b/exec/priv.h @@ -0,0 +1,153 @@ +/* GNU Hurd standard exec server, private declarations. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1999 Free Software Foundation, Inc. + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd 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. + +The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <hurd/trivfs.h> +#include <hurd/ports.h> +#include <hurd/lookup.h> +#include <rwlock.h> + +#ifdef BFD +#include <bfd.h> +#endif + +#include <elf.h> +#include <fcntl.h> +#include "exec_S.h" + + +#ifndef exec_priv_h +#define exec_priv_h + +#ifdef BFD +/* A BFD whose architecture and machine type are those of the host system. */ +extern bfd_arch_info_type host_bfd_arch_info; +extern bfd host_bfd; +#endif + +/* Information kept around to be given to a new task + in response to a message on the task's bootstrap port. */ +struct bootinfo + { + struct port_info pi; + vm_address_t stack_base; + vm_size_t stack_size; + int flags; + char *argv, *envp; + size_t argvlen, envplen, dtablesize, nports, nints; + mach_port_t *dtable, *portarray; + int *intarray; + vm_address_t phdr_addr, user_entry; + vm_size_t phdr_size; + }; + + +/* Where to put the service ports. */ +struct port_bucket *port_bucket; +struct port_class *execboot_portclass; + + +typedef struct trivfs_protid *trivfs_protid_t; /* For MiG. */ + +extern mach_port_t procserver; /* Our proc port. */ + +#ifndef BFD +typedef void asection; +#endif + +/* Data shared between check, check_section, + load, load_section, and finish. */ +struct execdata + { + /* Passed out to caller. */ + error_t error; + + /* Set by check. */ + vm_address_t entry; + FILE stream; + file_t file; + +#ifdef BFD + bfd *bfd; +#endif + union /* Interpreter section giving name of file. */ + { + asection *section; + const Elf32_Phdr *phdr; + } interp; + memory_object_t filemap, cntlmap; + struct shared_io *cntl; + char *file_data; /* File data if already copied in core. */ + off_t file_size; + size_t optimal_block; /* Optimal size for io_read from file. */ + + /* Set by caller of load. */ + task_t task; + + union + { + /* Vector indexed by section index, + information passed from check_section to load_section. + Set by caller of check_section and load. */ + vm_offset_t *bfd_locations; + struct + { + /* Program header table read from the executable. + After `check' this is a pointer into the mapping window. + By `load' it is local alloca'd storage. */ + Elf32_Phdr *phdr; + Elf32_Word phnum; /* Number of program header table elements. */ + int anywhere; /* Nonzero if image can go anywhere. */ + vm_address_t loadbase; /* Actual mapping location. */ + } elf; + } info; + }; + +error_t elf_machine_matches_host (Elf32_Half e_machine); + +void finish (struct execdata *, int dealloc_file_port); + +void check_hashbang (struct execdata *e, + file_t file, + task_t oldtask, + int flags, + char *argv, u_int argvlen, boolean_t argv_copy, + char *envp, u_int envplen, boolean_t envp_copy, + mach_port_t *dtable, u_int dtablesize, + boolean_t dtable_copy, + mach_port_t *portarray, u_int nports, + boolean_t portarray_copy, + int *intarray, u_int nints, boolean_t intarray_copy, + mach_port_t *deallocnames, u_int ndeallocnames, + mach_port_t *destroynames, u_int ndestroynames); + + +/* Standard exec data for secure execs. */ +extern mach_port_t *std_ports; +extern int *std_ints; +extern size_t std_nports, std_nints; +extern struct rwlock std_lock; + + +#endif /* exec_priv_h */ diff --git a/exec/tailor.h b/exec/tailor.h new file mode 100644 index 00000000..d207af55 --- /dev/null +++ b/exec/tailor.h @@ -0,0 +1,14 @@ + +#ifndef get_char +# define get_char() get_byte() +#endif + +#ifndef put_char +# define put_char(c) put_byte(c) +#endif + +#include <stdio.h> +#define fprintf(stream, fmt...) /* ignore useless error msgs */ ((void)0) + +void (*unzip_error) (const char *msg); +#define error(msg) (*unzip_error) (msg) diff --git a/exec/unzip.c b/exec/unzip.c new file mode 100644 index 00000000..d0f5bf11 --- /dev/null +++ b/exec/unzip.c @@ -0,0 +1,199 @@ +/* unzip.c -- decompress files in gzip or pkzip format. + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + * + * The code in this file is derived from the file funzip.c written + * and put in the public domain by Mark Adler. + */ + +/* + This version can extract files in gzip or pkzip format. + For the latter, only the first entry is extracted, and it has to be + either deflated or stored. + */ + +#ifdef RCSID +static char rcsid[] = "$Id: unzip.c,v 1.1 1994/12/14 04:30:25 roland Exp $"; +#endif + +#include "tailor.h" +#include "gzip.h" +#include "crypt.h" + +/* PKZIP header definitions */ +#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */ +#define LOCFLG 6 /* offset of bit flag */ +#define CRPFLG 1 /* bit for encrypted entry */ +#define EXTFLG 8 /* bit for extended local header */ +#define LOCHOW 8 /* offset of compression method */ +#define LOCTIM 10 /* file mod time (for decryption) */ +#define LOCCRC 14 /* offset of crc */ +#define LOCSIZ 18 /* offset of compressed size */ +#define LOCLEN 22 /* offset of uncompressed length */ +#define LOCFIL 26 /* offset of file name field length */ +#define LOCEXT 28 /* offset of extra field length */ +#define LOCHDR 30 /* size of local header, including sig */ +#define EXTHDR 16 /* size of extended local header, inc sig */ + + +/* Globals */ + +int decrypt; /* flag to turn on decryption */ +char *key; /* not used--needed to link crypt.c */ +int pkzip = 0; /* set for a pkzip file */ +int ext_header = 0; /* set if extended local header */ + +/* =========================================================================== + * Check zip file and advance inptr to the start of the compressed data. + * Get ofname from the local header if necessary. + */ +int check_zipfile(in) + int in; /* input file descriptors */ +{ + uch *h = inbuf + inptr; /* first local header */ + + ifd = in; + + /* Check validity of local header, and skip name and extra fields */ + inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT); + + if (inptr > insize || LG(h) != LOCSIG) { + fprintf(stderr, "\n%s: %s: not a valid zip file\n", + progname, ifname); + exit_code = ERROR; + return ERROR; + } + method = h[LOCHOW]; + if (method != STORED && method != DEFLATED) { + fprintf(stderr, + "\n%s: %s: first entry not deflated or stored -- use unzip\n", + progname, ifname); + exit_code = ERROR; + return ERROR; + } + + /* If entry encrypted, decrypt and validate encryption header */ + if ((decrypt = h[LOCFLG] & CRPFLG) != 0) { + fprintf(stderr, "\n%s: %s: encrypted file -- use unzip\n", + progname, ifname); + exit_code = ERROR; + return ERROR; + } + + /* Save flags for unzip() */ + ext_header = (h[LOCFLG] & EXTFLG) != 0; + pkzip = 1; + + /* Get ofname and time stamp from local header (to be done) */ + return OK; +} + +/* =========================================================================== + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + */ +int unzip(in, out) + int in, out; /* input and output file descriptors */ +{ + ulg orig_crc = 0; /* original crc */ + ulg orig_len = 0; /* original uncompressed length */ + int n; + uch buf[EXTHDR]; /* extended local header */ + + ifd = in; + ofd = out; + + updcrc(NULL, 0); /* initialize crc */ + + if (pkzip && !ext_header) { /* crc and length at the end otherwise */ + orig_crc = LG(inbuf + LOCCRC); + orig_len = LG(inbuf + LOCLEN); + } + + /* Decompress */ + if (method == DEFLATED) { + + int res = inflate(); + + if (res == 3) { + error("out of memory"); + } else if (res != 0) { + error("invalid compressed data--format violated"); + } + + } else if (pkzip && method == STORED) { + + register ulg n = LG(inbuf + LOCLEN); + + if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) { + + fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ)); + error("invalid compressed data--length mismatch"); + } + while (n--) { + uch c = (uch)get_byte(); +#ifdef CRYPT + if (decrypt) zdecode(c); +#endif + put_ubyte(c); + } + flush_window(); + } else { + error("internal error, invalid method"); + } + + /* Get the crc and original length */ + if (!pkzip) { + /* crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + for (n = 0; n < 8; n++) { + buf[n] = (uch)get_byte(); /* may cause an error if EOF */ + } + orig_crc = LG(buf); + orig_len = LG(buf+4); + + } else if (ext_header) { /* If extended header, check it */ + /* signature - 4bytes: 0x50 0x4b 0x07 0x08 + * CRC-32 value + * compressed size 4-bytes + * uncompressed size 4-bytes + */ + for (n = 0; n < EXTHDR; n++) { + buf[n] = (uch)get_byte(); /* may cause an error if EOF */ + } + orig_crc = LG(buf+4); + orig_len = LG(buf+12); + } + + /* Validate decompression */ + if (orig_crc != updcrc(outbuf, 0)) { + error("invalid compressed data--crc error"); + } + if (orig_len != (ulg)bytes_out) { + error("invalid compressed data--length error"); + } + + /* Check if there are more entries in a pkzip file */ + if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) { + if (to_stdout) { + WARN((stderr, + "%s: %s has more than one entry--rest ignored\n", + progname, ifname)); + } else { + /* Don't destroy the input zip file */ + fprintf(stderr, + "%s: %s has more than one entry -- unchanged\n", + progname, ifname); + exit_code = ERROR; + ext_header = pkzip = 0; + return ERROR; + } + } + ext_header = pkzip = 0; /* for next file */ + return OK; +} diff --git a/exec/util.c b/exec/util.c new file mode 100644 index 00000000..598586f5 --- /dev/null +++ b/exec/util.c @@ -0,0 +1,272 @@ +/* Hacked and slashed by roland@gnu.ai.mit.edu for use in Hurd exec server. */ + +/* util.c -- utility functions for gzip support + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +#ifdef RCSID +static char rcsid[] = "$Id: util.c,v 1.1 1994/12/14 04:29:37 roland Exp $"; +#endif + +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> + +#include "tailor.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifndef NO_FCNTL_H +# include <fcntl.h> +#endif + +#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H) +# include <stdlib.h> +#else + extern int errno; +#endif + +#include "gzip.h" +#include "crypt.h" + +/* cruft */ +int ifd, ofd; +int to_stdout=1,quiet=1; + +/* I/O interface */ +int (*unzip_read) (char *buf, size_t maxread); +void (*unzip_write) (const char *buf, size_t nwrite); +#define read_error() (*unzip_read_error) () +void (*unzip_read_error) (void); + + +extern ulg crc_32_tab[]; /* crc table, defined below */ + +int exit_code = OK; /* program exit code */ +int method = DEFLATED;/* compression method */ +unsigned insize; /* valid bytes in inbuf */ +unsigned inptr; /* index of next byte to be processed in inbuf */ +unsigned outcnt; /* bytes in output buffer */ +DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA); +DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); +DECLARE(uch, window, 2L*WSIZE); + + +/* This function stolen from gzip.c. */ +/* ======================================================================== + * Check the magic number of the input file and update ofname if an + * original name was given and to_stdout is not set. + * Return the compression method, -1 for error, -2 for warning. + * Set inptr to the offset of the next byte to be processed. + * Updates time_stamp if there is one and --no-time is not used. + * This function may be called repeatedly for an input file consisting + * of several contiguous gzip'ed members. + * IN assertions: there is at least one remaining compressed member. + * If the member is a zip file, it must be the only one. + */ +int get_method(in) + int in; /* input file descriptor */ +{ + uch flags; /* compression flags */ + char magic[2]; /* magic header */ + ulg stamp; /* time stamp */ + + /* Prime the input buffer. */ + fill_inbuf(0); + inptr = 0; + + magic[0] = (char)get_byte(); + magic[1] = (char)get_byte(); + + method = -1; /* unknown yet */ + + if (memcmp(magic, GZIP_MAGIC, 2) == 0 + || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { + + method = (int)get_byte(); + if (method != DEFLATED) + return -1; + + flags = (uch)get_byte(); + if ((flags & ENCRYPTED) != 0) return -1; + if ((flags & CONTINUATION) != 0) return -1; + if ((flags & RESERVED) != 0) return -1; + + stamp = (ulg)get_byte(); + stamp |= ((ulg)get_byte()) << 8; + stamp |= ((ulg)get_byte()) << 16; + stamp |= ((ulg)get_byte()) << 24; + + (void)get_byte(); /* Ignore extra flags for the moment */ + (void)get_byte(); /* Ignore OS type for the moment */ + + if ((flags & CONTINUATION) != 0) { + unsigned part = (unsigned)get_byte(); + part |= ((unsigned)get_byte())<<8; + } + if ((flags & EXTRA_FIELD) != 0) { + unsigned len = (unsigned)get_byte(); + len |= ((unsigned)get_byte())<<8; + while (len--) (void)get_byte(); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + /* Discard the old name */ + char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */ + do {c=get_byte();} while (c != 0); + } + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + while (get_char() != 0) /* null */ ; + } + } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 + && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) { + /* To simplify the code, we support a zip file when alone only. + * We are thus guaranteed that the entire local header fits in inbuf. + */ + inptr = 0; + if (check_zipfile(in) == OK) return 0; + } + + return method != DEFLATED; +} + + +/* =========================================================================== + * Run a set of bytes through the crc shift register. If s is a NULL + * pointer, then initialize the crc shift register contents instead. + * Return the current crc in either case. + */ +ulg updcrc(s, n) + uch *s; /* pointer to bytes to pump through */ + unsigned n; /* number of bytes in s[] */ +{ + register ulg c; /* temporary variable */ + + static ulg crc = (ulg)0xffffffffL; /* shift register contents */ + + if (s == NULL) { + c = 0xffffffffL; + } else { + c = crc; + if (n) do { + c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); + } while (--n); + } + crc = c; + return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} + +/* =========================================================================== + * Clear input and output buffers + */ +void clear_bufs() +{ + outcnt = 0; + insize = inptr = 0; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty. + */ +int fill_inbuf(eof_ok) + int eof_ok; /* set if EOF acceptable as a result */ +{ + int len; + + /* Read as much as possible */ + insize = 0; + do { + len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize); + if (len == 0 || len == EOF) break; + insize += len; + } while (insize < INBUFSIZ); + + if (insize == 0) { + if (eof_ok) return EOF; + read_error(); + } + + inptr = 1; + return inbuf[0]; +} + +long int bytes_out; + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +void flush_window() +{ + if (outcnt == 0) return; + updcrc(window, outcnt); + + (*unzip_write) ((char *) window, outcnt); + bytes_out += outcnt; + + outcnt = 0; +} + +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by makecrc.c) + */ +ulg crc_32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; |