aboutsummaryrefslogtreecommitdiff
path: root/exec
diff options
context:
space:
mode:
Diffstat (limited to 'exec')
-rw-r--r--exec/ChangeLog643
-rw-r--r--exec/Makefile26
-rw-r--r--exec/core.c264
-rw-r--r--exec/do-bunzip2.c1745
-rw-r--r--exec/elfcore.c630
-rw-r--r--exec/exec.c752
-rw-r--r--exec/execmutations.h2
-rw-r--r--exec/exectrans.c81
-rw-r--r--exec/gcore.c88
-rw-r--r--exec/hashexec.c205
-rw-r--r--exec/hostarch.c77
-rw-r--r--exec/main.c153
-rw-r--r--exec/priv.h71
13 files changed, 3200 insertions, 1537 deletions
diff --git a/exec/ChangeLog b/exec/ChangeLog
deleted file mode 100644
index d650dbd8..00000000
--- a/exec/ChangeLog
+++ /dev/null
@@ -1,643 +0,0 @@
-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
index 6a5d9525..e7050c10 100644
--- a/exec/Makefile
+++ b/exec/Makefile
@@ -1,6 +1,6 @@
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1993,94,95,96,98,99,2000,01,02,10 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)
@@ -10,7 +10,7 @@
# 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.
@@ -18,21 +18,27 @@
dir := exec
makemode := server
-SRCS = exec.c main.c hashexec.c hostarch.c unzip.c util.c inflate.c
+SRCS = exec.c main.c hashexec.c hostarch.c \
+ $(gzip-sources) $(bzip2-sources)
OBJS = main.o hostarch.o exec.o hashexec.o \
execServer.o exec_startupServer.o \
- $(gzip-objects)
-gzip-objects = unzip.o util.o inflate.o
+ $(gzip-objects) $(bzip2-objects)
+gzip-sources = unzip.c util.c inflate.c
+gzip-objects = $(gzip-sources:%.c=%.o)
+bzip2-sources = do-bunzip2.c
+bzip2-objects = $(bzip2-sources:%.c=%.o)
+
LCLHDRS = gzip.h crypt.h tailor.h priv.h execmutations.h
target = exec
-DIST_FILES = core.c gcore.c elfcore.c exectrans.c
+#targets = exec exec.static
+DIST_FILES = elfcore.c
#OTHERLIBS = -lbfd -liberty
+HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc
exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h
include ../Makeconf
-CPPFLAGS += -DGZIP # -DBFD
+CPPFLAGS += -DGZIP -DBZIP2 # -DBFD
-exec: ../libtrivfs/libtrivfs.so ../libthreads/libthreads.so \
- ../libshouldbeinlibc/libshouldbeinlibc.so ../libfshelp/libfshelp.so
+exec.static exec: $(OBJS) $(library_deps)
diff --git a/exec/core.c b/exec/core.c
deleted file mode 100644
index 6d685a23..00000000
--- a/exec/core.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* GNU Hurd standard core server.
- Copyright (C) 1992 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));
- vm_deallocate (mach_task_self (), 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/do-bunzip2.c b/exec/do-bunzip2.c
new file mode 100644
index 00000000..716a0cde
--- /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 disastrous 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
index 4388a135..f953cc76 100644
--- a/exec/elfcore.c
+++ b/exec/elfcore.c
@@ -1,100 +1,566 @@
+/* Write ELF core dump files for GNU Hurd.
+ Copyright (C) 2002, 2004, 2008 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 <elf.h>
+#include <link.h>
+#include <string.h>
+#include <argz.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+#include <sys/procfs.h>
+#include <stddef.h>
+
+#define ELF_CLASS PASTE (ELFCLASS, __ELF_NATIVE_CLASS)
+#define PASTE(a, b) PASTE_1 (a, b)
+#define PASTE_1(a, b) a##b
+
+#include <endian.h>
+#if BYTE_ORDER == BIG_ENDIAN
+#define ELF_DATA ELFDATA2MSB
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ELF_DATA ELFDATA2LSB
+#endif
+
+#include <mach/thread_status.h>
+#include <assert.h>
+
+#ifdef i386_THREAD_STATE
+# define ELF_MACHINE EM_386
+
+/* The gregset_t format (compatible with Linux/x86) almost fits
+ the Mach i386_thread_state. */
+static inline void
+fetch_thread_regset (thread_t thread, prgregset_t *gregs)
+{
+ union
+ {
+ struct i386_thread_state state;
+ prgregset_t gregs;
+ } *u = (void *) gregs;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+ assert (sizeof (struct i386_thread_state) < sizeof (prgregset_t));
+ assert (offsetof (struct i386_thread_state, gs) == REG_GS * 4);
+ assert (offsetof (struct i386_thread_state, eax) == REG_EAX * 4);
+
+ (void) thread_get_state (thread, i386_THREAD_STATE,
+ (thread_state_t) &u->state, &count);
+
+ u->gregs[REG_EIP] = u->state.eip;
+ u->gregs[REG_CS] = u->state.cs;
+ u->gregs[REG_EFL] = u->state.efl;
+ u->gregs[REG_UESP] = u->state.uesp;
+ u->gregs[REG_SS] = u->state.ss;
+
+ /* These are the extra words that don't exist in prgregset_t. */
+ u->gregs[REG_ERR] = u->gregs[REG_TRAPNO] = 0;
+}
+
+static inline void
+fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
+{
+ struct i386_float_state st;
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ error_t err = thread_get_state (thread, i386_FLOAT_STATE,
+ (thread_state_t) &st, &count);
+ if (err == 0 && st.initialized)
+ {
+ assert (sizeof *fpregs >= sizeof st.hw_state);
+ memcpy (fpregs, st.hw_state, sizeof st.hw_state);
+ }
+}
+
+#elif defined ALPHA_THREAD_STATE
+# define ELF_MACHINE EM_ALPHA
+
+/* The gregset_t format (compatible with Linux/Alpha) almost fits
+ the Mach alpha_thread_state. */
+static inline void
+fetch_thread_regset (thread_t thread, prgregset_t *gregs)
{
- processor_set_name_t pset;
- host_t host;
- processor_set_basic_info_data_t pinfo;
+ mach_msg_type_number_t count = ALPHA_THREAD_STATE_COUNT;
+ assert (sizeof (struct alpha_thread_state) <= sizeof (prgregset_t));
+ (void) thread_get_state (thread, ALPHA_THREAD_STATE,
+ (thread_state_t) gregs, &count);
+ /* XXX
+ gregs[32] is process-status word: Mach doesn't return it!
+ It's already zero'd.
+ */
+}
+/* The FPU state matches exactly. */
+static inline void
+fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
+{
+ mach_msg_type_number_t count = ALPHA_FLOAT_STATE_COUNT;
+ assert (sizeof (struct alpha_float_state) == sizeof *fpregs);
+ (void) thread_get_state (thread, ALPHA_FLOAT_STATE,
+ (thread_state_t) fpregs, &count);
+}
+
+#else
+# warning "do not understand this machine flavor, no registers in dumps"
+# define ELF_MACHINE EM_NONE
+#endif
+
+
+#define TIME_VALUE_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->seconds; \
+ (ts)->tv_nsec = (tv)->microseconds * 1000; \
+}
+
+#define PAGES_TO_KB(x) ((x) * (vm_page_size / 1024))
+#define ENCODE_PCT(f) ((uint16_t) ((f) * 32768.0))
+
+extern process_t procserver; /* crash.c */
+
+error_t
+dump_core (task_t task, file_t file, off_t corelimit,
+ int signo, long int sigcode, int sigerror)
+{
+ static float host_memory_size = -1.0;
+ error_t err;
+ ElfW(Phdr) *phdrs, *ph;
+ ElfW(Ehdr) hdr = /* ELF header for the core file. */
+ {
+ e_ident:
+ {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELF_CLASS,
+ [EI_DATA] = ELF_DATA,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_SYSV,
+ [EI_ABIVERSION] = 0
+ },
+ e_type: ET_CORE,
+ e_version: EV_CURRENT,
+ e_machine: ELF_MACHINE,
+ e_ehsize: sizeof hdr,
+ e_phentsize: sizeof phdrs[0],
+ e_phoff: sizeof hdr, /* Fill in e_phnum later. */
+ };
+ off_t offset;
+ size_t wrote;
+
+ pid_t pid;
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);
+ size_t nthreads, i;
+ off_t notestart;
+
+ /* Helper macros for writing notes. */
+#define DEFINE_NOTE(typename) struct { struct note_header hdr; typename data; }
+#define WRITE_NOTE(type, var) ({ \
+ (var).hdr = NOTE_HEADER ((type), sizeof (var).data); \
+ write_note (&(var).hdr); \
+})
+ struct note_header
+ {
+ ElfW(Nhdr) note;
+ char name[(sizeof "CORE" + 3) &~ 3];
+ } __attribute__ ((packed));
+#define NOTE_HEADER(type, size) \
+ ((struct note_header) { { sizeof "CORE", (size), (type) }, "CORE" })
+ inline error_t write_note (struct note_header *hdr)
+ {
+ error_t err = 0;
+ char *data = (char *) hdr;
+ size_t size = sizeof *hdr + hdr->note.n_descsz;
+ if (corelimit >= 0 && offset + size > corelimit)
+ size = corelimit - offset;
+ while (size > 0)
+ {
+ err = io_write (file, data, size, offset, &wrote);
+ if (err)
+ return err;
+ if (wrote > size)
+ return EGRATUITOUS;
+ data += wrote;
+ size -= wrote;
+ }
+ offset = (offset + wrote + 3) &~ 3; /* Pad it to word alignment. */
+ return 0;
+ }
+
+ struct vm_region_list
+ {
+ struct vm_region_list *next;
+ vm_prot_t protection;
+ vm_address_t start;
+ vm_size_t length;
+ };
+ struct vm_region_list *regions = NULL, **tailp = &regions, *r;
+ unsigned int nregions = 0;
+
+ if (corelimit >= 0 && corelimit < sizeof hdr)
+ return EFBIG;
+
+ {
+ /* Examine the task and record the locations of contiguous memory
+ segments that we will dump into the core file. */
+
+ vm_address_t region_address, last_region_address, last_region_end;
+ vm_prot_t last_protection;
+#define RECORD_LAST_REGION do { \
+ if (last_region_end > last_region_address \
+ && last_protection != VM_PROT_NONE) \
+ record_last_region (alloca (sizeof (struct vm_region_list))); } while (0)
+ inline void record_last_region (struct vm_region_list *region)
+ {
+ *tailp = region;
+ tailp = &region->next;
+ region->next = NULL;
+ region->start = last_region_address;
+ region->length = last_region_end - last_region_address;
+ region->protection = last_protection;
+ ++nregions;
+ }
+
+ region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
+ last_protection = VM_PROT_NONE;
+ while (region_address < VM_MAX_ADDRESS)
+ {
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ vm_size_t region_length = VM_MAX_ADDRESS - region_address;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ if (err == KERN_NO_SPACE)
+ break;
+ if (err != KERN_SUCCESS)
+ return err;
+
+ if (protection == last_protection && region_address == last_region_end)
+ /* This region is contiguous with and indistinguishable from
+ the previous one, so we just extend that one. */
+ last_region_end = region_address += region_length;
+ else
+ {
+ /* This region is distinct from the last one we saw,
+ so record that previous one. */
+ RECORD_LAST_REGION;
+ last_region_address = region_address;
+ last_region_end = region_address += region_length;
+ last_protection = protection;
+ }
+ }
+ /* Record the final region. */
+ RECORD_LAST_REGION;
+ }
+
+ /* Now we start laying out the file. */
+ offset = sizeof hdr + ((nregions + 1) * sizeof *phdrs);
+
+ /* Final check for tiny core limit. From now on, we will simply truncate
+ the file at CORELIMIT but not change the contents of what we write. */
+ if (corelimit >= 0 && corelimit < offset)
+ return EFBIG;
+
+ /* Now we can complete the file header and write it. */
+ hdr.e_phnum = nregions + 1;
+ err = io_write (file, (char *) &hdr, sizeof hdr, 0, &wrote);
if (err)
- goto lose;
+ return err;
+ if (wrote < sizeof hdr)
+ return EGRATUITOUS; /* XXX */
+
+ /* Now we can write the various notes. */
+ notestart = offset;
- if (err = task_threads (task, &threads, &nthreads))
- goto lose;
+ /* First a dull note containing the results of `uname', a la Solaris. */
+ {
+ DEFINE_NOTE (struct utsname) note;
+ if (uname (&note.data) == 0) /* XXX Use proc_uname on task's proc port? */
+ err = WRITE_NOTE (NT_UTSNAME, note);
+ }
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
- /* 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))
+ err = proc_task2pid (procserver, task, &pid);
+ if (err)
+ return err;
+
+ /* Make sure we have the total RAM size of the host.
+ We only do this once, assuming that it won't change.
+ XXX this could use the task's host-self port instead. */
+ if (host_memory_size <= 0.0)
{
- mach_port_deallocate (mach_task_self (), objname);
+ host_basic_info_data_t hostinfo;
+ mach_msg_type_number_t size = sizeof hostinfo;
+ error_t err = host_info (mach_host_self (), HOST_BASIC_INFO,
+ (host_info_t) &hostinfo, &size);
+ if (err == 0)
+ host_memory_size = hostinfo.memory_size;
+ }
+
+ /* The psinfo_t note contains some process-global info we should get from
+ the proc server, but no thread-specific info like register state. */
+ {
+ DEFINE_NOTE (psinfo_t) psinfo;
+ DEFINE_NOTE (pstatus_t) pstatus;
+ int flags = PI_FETCH_TASKINFO | PI_FETCH_THREADS | PI_FETCH_THREAD_BASIC;
+ char *waits = 0;
+ mach_msg_type_number_t num_waits = 0;
+ char pibuf[offsetof (struct procinfo, threadinfos[2])];
+ struct procinfo *pi = (void *) &pibuf;
+ mach_msg_type_number_t pi_size = sizeof pibuf;
+
+ memset (&pstatus.data, 0, sizeof pstatus.data);
+ memset (&psinfo.data, 0, sizeof psinfo.data);
+ pstatus.data.pr_pid = psinfo.data.pr_pid = pid;
+
+ err = proc_getprocinfo (procserver, pid, &flags,
+ (procinfo_t *) &pi, &pi_size,
+ &waits, &num_waits);
+ if (err == 0)
+ {
+ if (num_waits != 0)
+ munmap (waits, num_waits);
+
+ pstatus.data.pr_flags = psinfo.data.pr_flag = pi->state;
+ pstatus.data.pr_nlwp = psinfo.data.pr_nlwp = pi->nthreads;
+ pstatus.data.pr_ppid = psinfo.data.pr_ppid = pi->ppid;
+ pstatus.data.pr_pgid = psinfo.data.pr_pgid = pi->pgrp;
+ pstatus.data.pr_sid = psinfo.data.pr_sid = pi->session;
+
+ psinfo.data.pr_euid = pi->owner;
+ /* XXX struct procinfo should have these */
+ psinfo.data.pr_egid = psinfo.data.pr_gid = psinfo.data.pr_uid = -1;
+
+ psinfo.data.pr_size = PAGES_TO_KB (pi->taskinfo.virtual_size);
+ psinfo.data.pr_rssize = PAGES_TO_KB (pi->taskinfo.resident_size);
+
+ {
+ /* Sum all the threads' cpu_usage fields. */
+ integer_t cpu_usage = 0;
+ for (i = 0; i < pi->nthreads; ++i)
+ cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
+ psinfo.data.pr_pctcpu = ENCODE_PCT ((float) cpu_usage
+ / (float) TH_USAGE_SCALE);
+ }
+ if (host_memory_size > 0.0)
+ psinfo.data.pr_pctmem
+ = ENCODE_PCT
+ ((float) pi->taskinfo.resident_size / host_memory_size);
+
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.creation_time,
+ &psinfo.data.pr_start);
- if (prot != VM_PROT_NONE)
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time,
+ &pstatus.data.pr_utime);
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.system_time,
+ &pstatus.data.pr_stime);
+ /* Sum the user and system time for pr_time. */
+ pi->taskinfo.user_time.seconds += pi->taskinfo.system_time.seconds;
+ pi->taskinfo.user_time.microseconds += pi->taskinfo.system_time.microseconds;
+ if (pi->taskinfo.user_time.microseconds >= 1000000)
+ {
+ ++pi->taskinfo.user_time.seconds;
+ pi->taskinfo.user_time.microseconds -= 1000000;
+ }
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, &psinfo.data.pr_time);
+ /* XXX struct procinfo should have dead child info for pr_c[us]?time */
+
+ psinfo.data.pr_wstat = pi->exitstatus;
+
+ if ((void *) pi != &pibuf)
+ munmap (pi, pi_size);
+ }
+ if (err == 0)
+ {
+ /* We have to nab the process's own proc port to get the
+ proc server to tell us its registered arg locations. */
+ process_t proc;
+ err = proc_task2proc (procserver, task, &proc);
+ if (err == 0)
+ {
+ err = proc_get_arg_locations (proc,
+ &psinfo.data.pr_argv,
+ &psinfo.data.pr_envp);
+ mach_port_deallocate (mach_task_self (), proc);
+ }
{
- 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
+ /* Now fetch the arguments. We could do this directly from the
+ task given the locations we now have. But we are lazy and have
+ the proc server do it for us. */
+ char *data = psinfo.data.pr_psargs;
+ size_t datalen = sizeof psinfo.data.pr_psargs;
+ err = proc_getprocargs (procserver, pid, &data, &datalen);
+ if (err == 0)
{
- /* 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)
+ psinfo.data.pr_argc = argz_count (data, datalen);
+ argz_stringify (data, datalen, ' ');
+ if (data != psinfo.data.pr_psargs)
{
- /* 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;
+ memcpy (psinfo.data.pr_psargs, data,
+ sizeof psinfo.data.pr_psargs);
+ munmap (data, datalen);
}
- 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);
}
}
+ err = WRITE_NOTE (NT_PSINFO, psinfo);
+ }
+
+ err = WRITE_NOTE (NT_PSTATUS, pstatus) ?: err;
+ }
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
+
+ /* Now examine all the threads in the task.
+ For each thread we produce one or more notes. */
+ err = task_threads (task, &threads, &nthreads);
+ if (err)
+ return err;
+ for (i = 0; i < nthreads; ++i)
+ {
+ DEFINE_NOTE (lwpstatus_t) note;
+ memset (&note.data, 0, sizeof note.data);
+ note.data.pr_lwpid = i;
+
+ /* We have to write the death signal into every thread's record, even
+ though only one thread really took the signal. This is both because
+ we don't know which thread it was, and because GDB blindly uses the
+ value from each record to clobber the last (even if it's zero). */
+ note.data.pr_cursig = signo;
+ note.data.pr_info.si_signo = signo;
+ note.data.pr_info.si_code = sigcode;
+ note.data.pr_info.si_errno = sigerror;
+
+ fetch_thread_regset (threads[i], &note.data.pr_reg);
+ fetch_thread_fpregset (threads[i], &note.data.pr_fpreg);
+
+ err = WRITE_NOTE (NT_LWPSTATUS, note);
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ break;
+
+ mach_port_deallocate (mach_task_self (), threads[i]);
}
+ /* If we broke out of the loop early, deallocate remaining thread ports. */
+ while (i < nthreads)
+ mach_port_deallocate (mach_task_self (), threads[i++]);
+ munmap (threads, nthreads * sizeof *threads);
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
- /* Write all the sections' data. */
- for (sec = bfd->sections; sec != NULL; sec = sec->next)
+ /* Make an array of program headers and fill them in.
+ The first one describes the note segment. */
+ ph = phdrs = alloca ((nregions + 1) * sizeof *phdrs);
+
+ memset (ph, 0, sizeof *ph);
+ ph->p_type = PT_NOTE;
+ ph->p_offset = notestart;
+ ph->p_filesz = offset - notestart;
+ ++ph;
+
+ /* Now make ELF program headers for each of the recorded memory regions.
+ Consistent with the Linux kernel, we create PT_LOAD headers with
+ p_filesz = 0 for the read-only segments that we are not dumping
+ into the file. */
+ for (r = regions; r != NULL; r = r->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));
- vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec));
- if (err)
- goto bfdlose;
+ memset (ph, 0, sizeof *ph);
+ ph->p_type = PT_LOAD;
+ ph->p_align = vm_page_size;
+ ph->p_flags = (((r->protection & VM_PROT_READ) ? PF_R : 0)
+ | ((r->protection & VM_PROT_WRITE) ? PF_W : 0)
+ | ((r->protection & VM_PROT_EXECUTE) ? PF_X : 0));
+ ph->p_vaddr = r->start;
+ ph->p_memsz = r->length;
+ ph->p_filesz = (r->protection & VM_PROT_WRITE) ? ph->p_memsz : 0;
+ ph->p_offset = round_page (offset);
+ offset += ph->p_filesz;
+ ++ph;
}
+
+ /* Now write the memory segment data. */
+ for (ph = &phdrs[1]; ph < &phdrs[nregions + 1]; ++ph)
+ if (ph->p_filesz > 0)
+ {
+ vm_address_t va = ph->p_vaddr;
+ vm_size_t sz = ph->p_memsz;
+ off_t ofs = ph->p_offset;
+ int wrote_any = 0;
+ do
+ {
+ pointer_t copied;
+ size_t copy_count;
+ err = vm_read (task, va, sz, &copied, &copy_count);
+ if (err == 0)
+ {
+ char *data = (void *) copied;
+ size_t left = copy_count, wrote;
+
+ va += copy_count;
+ sz -= copy_count;
+
+ do
+ {
+ if (corelimit >= 0 && ofs + left > corelimit)
+ left = corelimit - ofs;
+ err = io_write (file, data, left, ofs, &wrote);
+ if (err)
+ break;
+ ofs += wrote;
+ data += wrote;
+ left -= wrote;
+ if (ofs >= corelimit)
+ break;
+ } while (left > 0);
+
+ munmap ((void *) copied, copy_count);
+
+ if (left < copy_count)
+ wrote_any = 1;
+ }
+ else
+ {
+ /* Leave a hole in the file for pages we can't read. */
+ va += vm_page_size;
+ sz -= vm_page_size;
+ ofs += vm_page_size;
+ }
+ } while (sz > 0 && (corelimit < 0 || ofs < corelimit));
+
+ if (! wrote_any)
+ /* If we failed to write any contents at all,
+ don't claim the big hole as the contents. */
+ ph->p_filesz = 0;
+ }
+
+ /* Finally, we go back and write the program headers. */
+ err = io_write (file, (char *) phdrs, (nregions + 1) * sizeof phdrs[0],
+ sizeof hdr, &wrote);
+
+ return err;
+}
diff --git a/exec/exec.c b/exec/exec.c
index a9de454a..4c2fcec1 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -1,5 +1,6 @@
/* GNU Hurd standard exec server.
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,98,99,2000,01,02,04
+ Free Software Foundation, Inc.
Written by Roland McGrath.
Can exec ELF format directly.
@@ -10,6 +11,9 @@
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.
@@ -32,9 +36,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <hurd.h>
#include <hurd/exec.h>
-#include <hurd/shared.h>
#include <sys/stat.h>
+#include <sys/param.h>
#include <unistd.h>
+#include <stdbool.h>
mach_port_t procserver; /* Our proc port. */
@@ -70,6 +75,10 @@ b2he (error_t deflt)
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]. */
@@ -132,7 +141,7 @@ load_section (void *section, struct execdata *u)
#ifdef BFD
asection *const sec = section;
#endif
- const Elf32_Phdr *const ph = section;
+ const ElfW(Phdr) *const ph = section;
if (u->error)
return;
@@ -173,6 +182,7 @@ load_section (void *section, struct execdata *u)
if (! anywhere)
addr += u->info.elf.loadbase;
else
+#if 0
switch (elf_machine)
{
case EM_386:
@@ -187,6 +197,9 @@ load_section (void *section, struct execdata *u)
default:
break;
}
+#endif
+ if (anywhere && addr < vm_page_size)
+ addr = vm_page_size;
}
if (memsz == 0)
@@ -214,16 +227,19 @@ load_section (void *section, struct execdata *u)
if (! u->error && off != 0)
{
vm_address_t page = 0;
- u->error = vm_allocate (mach_task_self (),
- &page, vm_page_size, 1);
+ 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,
+ u->error = hurd_safe_copyin ((void *) page, /* XXX/fault */
(void *) (contents + (size - off)),
off);
- u->error = vm_write (u->task, mapstart + (size - off),
- page, vm_page_size);
- vm_deallocate (mach_task_self (), page, vm_page_size);
+ if (! u->error)
+ 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. */
@@ -256,21 +272,10 @@ load_section (void *section, struct execdata *u)
{
/* 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);
- u->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &buf, size, 1);
- 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);
- vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
- }
+ void *buf = map (u, filepos + (mapstart - addr), size);
+ if (buf)
+ write_to_task (mapstart, size, vm_prot, (vm_address_t) buf);
}
if (u->error)
return;
@@ -308,8 +313,12 @@ load_section (void *section, struct execdata *u)
&overlap_page, vm_page_size, 0);
size = vm_page_size;
if (!u->error)
- u->error = vm_allocate (mach_task_self (),
- &ourpage, vm_page_size, 1);
+ {
+ 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)
{
@@ -325,14 +334,17 @@ load_section (void *section, struct execdata *u)
readsize = filesz;
if (SECTION_IN_MEMORY_P)
- bcopy (SECTION_CONTENTS, readaddr, readsize);
+ memcpy (readaddr, SECTION_CONTENTS, readsize);
else
- if (fseek (&u->stream, filepos, SEEK_SET) ||
- fread (readaddr, readsize, 1, &u->stream) != 1)
- {
- u->error = errno;
+ {
+ const void *contents = map (u, filepos, readsize);
+ if (!contents)
goto maplose;
- }
+ u->error = hurd_safe_copyin (readaddr, contents,
+ readsize); /* XXX/fault */
+ if (u->error)
+ goto maplose;
+ }
u->error = vm_write (u->task, overlap_page, ourpage, size);
if (u->error == KERN_PROTECTION_FAILURE)
{
@@ -349,7 +361,7 @@ load_section (void *section, struct execdata *u)
u->error = vm_protect (u->task, overlap_page, size,
0, vm_prot);
}
- vm_deallocate (mach_task_self (), ourpage, size);
+ munmap ((caddr_t) ourpage, size);
if (u->error)
goto maplose;
}
@@ -412,15 +424,122 @@ load_section (void *section, struct execdata *u)
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);
- vm_deallocate (mach_task_self (), ourpage, size);
+ munmap ((caddr_t) ourpage, size);
}
}
}
-/* Make sure our mapping window (or read buffer) covers
- LEN bytes of the file starting at POSN. */
+/* XXX all accesses of the mapped data need to use fault handling
+ to abort the RPC when mapped file data generates bad page faults.
+ I've marked some accesses with XXX/fault comments.
+ --roland */
-static void *
+void *
+map (struct execdata *e, off_t posn, size_t len)
+{
+ const size_t size = e->file_size;
+ size_t offset;
+
+ if ((map_filepos (e) & ~(map_vsize (e) - 1)) == (posn & ~(map_vsize (e) - 1))
+ && posn + len - map_filepos (e) <= map_fsize (e))
+ /* The current mapping window covers it. */
+ offset = posn & (map_vsize (e) - 1);
+ else if (posn + len > size)
+ /* The requested data wouldn't fit in the file. */
+ return NULL;
+ else if (e->file_data != NULL) {
+ return e->file_data + posn;
+ } else if (e->filemap == MACH_PORT_NULL)
+ {
+ /* No mapping for the file. Read the data by RPC. */
+ char *buffer = map_buffer (e);
+ mach_msg_type_number_t nread = map_vsize (e);
+
+ assert (e->file_data == NULL); /* Must be first or second case. */
+
+ /* 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)
+ return NULL;
+ if (buffer != map_buffer (e))
+ {
+ /* The data was returned out of line. Discard the old buffer. */
+ if (map_vsize (e) != 0)
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = buffer;
+ map_vsize (e) = round_page (nread);
+ }
+
+ map_filepos (e) = posn;
+ map_set_fsize (e, nread);
+ offset = 0;
+ }
+ else
+ {
+ /* Deallocate the old mapping area. */
+ if (map_buffer (e) != NULL)
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = NULL;
+
+ /* Make sure our mapping is page-aligned in the file. */
+ offset = posn & (vm_page_size - 1);
+ map_filepos (e) = trunc_page (posn);
+ map_vsize (e) = round_page (posn + len) - map_filepos (e);
+
+ /* Map the data from the file. */
+ if (vm_map (mach_task_self (),
+ (vm_address_t *) &map_buffer (e), map_vsize (e), 0, 1,
+ e->filemap, map_filepos (e), 1, VM_PROT_READ, VM_PROT_READ,
+ VM_INHERIT_NONE))
+ {
+ e->error = EIO;
+ return NULL;
+ }
+
+ if (e->cntl)
+ e->cntl->accessed = 1;
+
+ map_set_fsize (e, MIN (map_vsize (e), size - map_filepos (e)));
+ }
+
+ return map_buffer (e) + offset;
+}
+
+
+/* Initialize E's stdio stream. */
+static void prepare_stream (struct execdata *e);
+
+/* Point the stream at the buffer of file data in E->file_data. */
+static void prepare_in_memory (struct execdata *e);
+
+
+#ifndef EXECDATA_STREAM
+
+/* We don't have a stdio stream, but we have a mapping window
+ we need to initialize. */
+static void
+prepare_stream (struct execdata *e)
+{
+ e->map_buffer = NULL;
+ e->map_vsize = e->map_fsize = 0;
+ e->map_filepos = 0;
+}
+
+static void prepare_in_memory (struct execdata *e)
+{
+ prepare_stream(e);
+}
+
+#else
+
+#ifdef _STDIO_USES_IOSTREAM
+
+# error implement me for libio!
+
+#else /* old GNU stdio */
+
+#if 0
+void *
map (struct execdata *e, off_t posn, size_t len)
{
FILE *f = &e->stream;
@@ -431,6 +550,13 @@ map (struct execdata *e, off_t posn, size_t len)
f->__buffer + (posn + len - f->__offset) < f->__get_limit)
/* The current mapping window covers it. */
offset = posn & (f->__bufsize - 1);
+ else if (e->file_data != NULL)
+ {
+ /* The current "mapping window" is in fact the whole file contents.
+ So if it's not in there, it's not in there. */
+ f->__eof = 1;
+ return NULL;
+ }
else if (e->filemap == MACH_PORT_NULL)
{
/* No mapping for the file. Read the data by RPC. */
@@ -448,8 +574,7 @@ map (struct execdata *e, off_t posn, size_t len)
{
/* The data was returned out of line. Discard the old buffer. */
if (f->__bufsize != 0)
- vm_deallocate (mach_task_self (),
- (vm_address_t) f->__buffer, f->__bufsize);
+ munmap (f->__buffer, f->__bufsize);
f->__buffer = buffer;
f->__bufsize = round_page (nread);
}
@@ -462,8 +587,7 @@ map (struct execdata *e, off_t posn, size_t len)
{
/* Deallocate the old mapping area. */
if (f->__buffer != NULL)
- vm_deallocate (mach_task_self (), (vm_address_t) f->__buffer,
- f->__bufsize);
+ munmap (f->__buffer, f->__bufsize);
f->__buffer = NULL;
/* Make sure our mapping is page-aligned in the file. */
@@ -474,7 +598,7 @@ map (struct execdata *e, off_t posn, size_t len)
/* Map the data from the file. */
if (vm_map (mach_task_self (),
(vm_address_t *) &f->__buffer, f->__bufsize, 0, 1,
- e->filemap, f->__target, 1, VM_PROT_READ, VM_PROT_READ,
+ e->filemap, f->__offset, 1, VM_PROT_READ, VM_PROT_READ,
VM_INHERIT_NONE))
{
errno = e->error = EIO;
@@ -486,7 +610,7 @@ map (struct execdata *e, off_t posn, size_t len)
e->cntl->accessed = 1;
if (f->__offset + f->__bufsize > size)
- f->__get_limit = f->__buffer + (size - f->__target);
+ f->__get_limit = f->__buffer + (size - f->__offset);
else
f->__get_limit = f->__buffer + f->__bufsize;
}
@@ -502,13 +626,26 @@ map (struct execdata *e, off_t posn, size_t len)
return f->__bufp;
}
+#endif
-/* stdio input-room function. */
+/* stdio input-room function.
+ XXX/fault in the stdio case (or libio replacement), i.e. for bfd
+ (if ever revived), need to check all the mapping fault issues */
static int
input_room (FILE *f)
{
- return (map (f->__cookie, f->__target, 1) == NULL ? EOF :
- (unsigned char) *f->__bufp++);
+ struct execdata *e = f->__cookie;
+ char *p = map (e, f->__target, 1);
+ if (p == NULL)
+ {
+ (e->error ? f->__error : f->__eof) = 1;
+ return EOF;
+ }
+
+ f->__target = f->__offset;
+ f->__bufp = p;
+
+ return (unsigned char) *f->__bufp++;
}
static int
@@ -517,12 +654,68 @@ close_exec_stream (void *cookie)
struct execdata *e = cookie;
if (e->stream.__buffer != NULL)
- vm_deallocate (mach_task_self (), (vm_address_t) e->stream.__buffer,
- e->stream.__bufsize);
+ 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;
}
+/* Initialize E's stdio stream. */
+static void
+prepare_stream (struct execdata *e)
+{
+ 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;
+}
+
+/* Point the stream at the buffer of file data. */
+static void
+prepare_in_memory (struct execdata *e)
+{
+ 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
+
+#endif
+
/* Prepare to check and load FILE. */
static void
@@ -543,16 +736,7 @@ prepare (file_t file, struct execdata *e)
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;
- /* This never gets called, but fseek returns ESPIPE if it's null. */
- e->stream.__io_funcs.seek = __default_io_functions.seek;
- e->stream.__io_funcs.close = close_exec_stream;
- e->stream.__cookie = e;
- e->stream.__seen = 1;
+ prepare_stream (e);
/* Try to mmap FILE. */
e->error = io_map (file, &rd, &wr);
@@ -569,17 +753,7 @@ prepare (file_t file, struct execdata *e)
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
+ if (!e->error)
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,
@@ -617,9 +791,17 @@ prepare (file_t file, struct execdata *e)
break;
}
}
- else if (e->error == EOPNOTSUPP)
- /* We can't mmap FILE, but perhaps we can do normal I/O to it. */
- e->error = 0;
+
+ if (!e->cntl && (!e->error || e->error == EOPNOTSUPP))
+ {
+ /* 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;
+ }
}
/* Check the magic number, etc. of the file.
@@ -669,18 +851,18 @@ check_bfd (struct execdata *e)
static void
check_elf (struct execdata *e)
{
- Elf32_Ehdr *ehdr = map (e, 0, sizeof (Elf32_Ehdr));
- Elf32_Phdr *phdr;
+ ElfW(Ehdr) *ehdr = map (e, 0, sizeof (ElfW(Ehdr)));
+ ElfW(Phdr) *phdr;
if (! ehdr)
{
- if (! ferror (&e->stream))
+ if (!e->error)
e->error = ENOEXEC;
return;
}
- if (*(Elf32_Word *) ehdr != ((union { Elf32_Word word;
- unsigned char string[SELFMAG]; })
+ if (*(ElfW(Word) *) ehdr != ((union { ElfW(Word) word;
+ unsigned char string[SELFMAG]; })
{ string: ELFMAG }).word)
{
e->error = ENOEXEC;
@@ -691,13 +873,15 @@ check_elf (struct execdata *e)
ehdr->e_ident[EI_DATA] != host_ELFDATA ||
ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
ehdr->e_version != EV_CURRENT ||
- ehdr->e_machine != elf_machine ||
ehdr->e_ehsize < sizeof *ehdr ||
- ehdr->e_phentsize != sizeof (Elf32_Phdr))
+ ehdr->e_phentsize != sizeof (ElfW(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. */
@@ -707,24 +891,33 @@ check_elf (struct execdata *e)
e->info.elf.loadbase = 0;
e->info.elf.phnum = ehdr->e_phnum;
- phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr));
+ phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (ElfW(Phdr)));
if (! phdr)
{
- if (! ferror (&e->stream))
+ if (!e->error)
e->error = ENOEXEC;
return;
}
e->info.elf.phdr = phdr;
+ e->info.elf.phdr_addr = ehdr->e_phoff;
}
+/* Copy MAPPED_PHDR into E->info.elf.phdr, filling in E->interp.phdr
+ in the process. */
static void
-check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr,
- vm_address_t *phdr_addr, vm_size_t *phdr_size)
+check_elf_phdr (struct execdata *e, const ElfW(Phdr) *mapped_phdr)
{
- const Elf32_Phdr *phdr;
+ const ElfW(Phdr) *phdr;
+ bool seen_phdr = false;
memcpy (e->info.elf.phdr, mapped_phdr,
- e->info.elf.phnum * sizeof (Elf32_Phdr));
+ e->info.elf.phnum * sizeof (ElfW(Phdr)));
+
+ /* Default state if we do not see PT_GNU_STACK telling us what to do.
+ Executable stack is the compatible default.
+ (XXX should be machine-dependent??)
+ */
+ e->info.elf.execstack = 1;
for (phdr = e->info.elf.phdr;
phdr < &e->info.elf.phdr[e->info.elf.phnum];
@@ -734,26 +927,37 @@ check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr,
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;
+ {
+ e->error = ENOEXEC;
+ return;
+ }
+ /* Check if this is the segment that contains the phdr image. */
+ if (!seen_phdr
+ && (phdr->p_offset & -phdr->p_align) == 0 /* Sanity check. */
+ && phdr->p_offset <= e->info.elf.phdr_addr
+ && e->info.elf.phdr_addr - phdr->p_offset < phdr->p_filesz)
+ {
+ e->info.elf.phdr_addr += phdr->p_vaddr - phdr->p_offset;
+ seen_phdr = true;
+ }
+ break;
+ case PT_GNU_STACK:
+ e->info.elf.execstack = phdr->p_flags & PF_X;
break;
}
+
+ if (!seen_phdr)
+ e->info.elf.phdr_addr = 0;
}
static void
check (struct execdata *e)
{
- check_elf (e);
+ check_elf (e); /* XXX/fault */
#ifdef BFD
if (e->error == ENOEXEC)
{
@@ -781,7 +985,7 @@ finish_mapping (struct execdata *e)
e->cntl->conch_status = USER_HAS_NOT_CONCH;
spin_unlock (&e->cntl->lock);
}
- vm_deallocate (mach_task_self (), (vm_address_t) e->cntl, vm_page_size);
+ munmap (e->cntl, vm_page_size);
e->cntl = NULL;
}
if (e->filemap != MACH_PORT_NULL)
@@ -796,7 +1000,9 @@ finish_mapping (struct execdata *e)
}
}
-/* Clean up after reading the file (need not be completed). */
+/* Clean up after reading the file (need not be completed).
+ Note: this may be called several times for the E, so it must take care
+ of checking what was already freed. */
void
finish (struct execdata *e, int dealloc_file)
{
@@ -809,7 +1015,19 @@ finish (struct execdata *e, int dealloc_file)
}
else
#endif
- fclose (&e->stream);
+ {
+#ifdef EXECDATA_STREAM
+ fclose (&e->stream);
+#else
+ if (e->file_data != NULL) {
+ free (e->file_data);
+ e->file_data = NULL;
+ } else if (map_buffer (e) != NULL) {
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = NULL;
+ }
+#endif
+ }
if (dealloc_file && e->file != MACH_PORT_NULL)
{
mach_port_deallocate (mach_task_self (), e->file);
@@ -838,12 +1056,12 @@ load (task_t usertask, struct execdata *e)
else
#endif
{
- Elf32_Word i;
+ ElfW(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
+ /* The entry point address is relative to wherever we loaded the
program text. */
e->entry += e->info.elf.loadbase;
}
@@ -893,7 +1111,7 @@ load (task_t usertask, struct execdata *e)
/* Force it to be paged in. */
(void) *(volatile int *) a;
- vm_deallocate (mach_task_self (), myaddr, mysize);
+ munmap ((caddr_t) myaddr, mysize);
}
}
@@ -927,9 +1145,23 @@ check_gzip (struct execdata *earg)
size_t zipdatasz = 0;
FILE *zipout = NULL;
jmp_buf ziperr;
+ off_t zipread_pos = 0;
int zipread (char *buf, size_t maxread)
{
- return fread (buf, 1, maxread, &e->stream);
+ char *contents = map (e, zipread_pos, 1);
+ size_t n;
+ if (contents == NULL)
+ {
+ errno = e->error;
+ return -1;
+ }
+ n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
+ errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
+ if (errno)
+ longjmp (ziperr, 2);
+
+ zipread_pos += n;
+ return n;
}
void zipwrite (const char *buf, size_t nwrite)
{
@@ -964,7 +1196,6 @@ check_gzip (struct execdata *earg)
return;
}
- rewind (&e->stream);
if (get_method (0) != 0)
{
/* Not a happy gzip file. */
@@ -989,41 +1220,136 @@ check_gzip (struct execdata *earg)
/* The output is complete. Clean up the stream and store its resultant
buffer and size in the execdata as the file contents. */
fclose (zipout);
+
+ /* Clean up the old exec file stream's state.
+ Now that we have the contents all in memory (in E->file_data),
+ nothing will in fact ever try to use E->stream again. */
+ finish (e, 0);
+
+ /* Prepare the stream state to use the file contents already in memory. */
e->file_data = zipdata;
e->file_size = zipdatasz;
+ prepare_in_memory (e);
+}
+#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;
+ off_t zipread_pos = 0;
+ int zipread (char *buf, size_t maxread)
+ {
+ char *contents = map (e, zipread_pos, 1);
+ size_t n;
+ if (contents == NULL)
+ {
+ errno = e->error;
+ return -1;
+ }
+ n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
+ errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
+ if (errno)
+ longjmp (ziperr, 2);
+
+ zipread_pos += n;
+ return n;
+ }
+ 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;
+ }
+
+ zipout = open_memstream (&zipdata, &zipdatasz);
+ if (! zipout)
+ {
+ e->error = errno;
+ return;
+ }
- /* Clean up the old exec file stream's state. */
+ /* 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);
+
+ /* Clean up the old exec file stream's state.
+ Now that we have the contents all in memory (in E->file_data),
+ nothing will in fact ever try to use E->stream again. */
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;
+ /* Prepare the stream state to use the file contents already in memory. */
+ e->file_data = zipdata;
+ e->file_size = zipdatasz;
+ prepare_in_memory (e);
}
#endif
-static inline error_t
-servercopy (void **arg, mach_msg_type_number_t argsize, boolean_t argcopy)
+static inline void *
+servercopy (void *arg, mach_msg_type_number_t argsize, boolean_t argcopy,
+ error_t *errorp)
{
- if (argcopy)
- {
- /* ARG came in-line, so we must copy it. */
- error_t error;
- void *copy;
- error = vm_allocate (mach_task_self (),
- (vm_address_t *) &copy, argsize, 1);
- if (error)
- return error;
- bcopy (*arg, copy, argsize);
- *arg = copy;
+ if (! argcopy)
+ return arg;
+
+ /* 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 == MAP_FAILED)
+ {
+ *errorp = errno;
+ return NULL;
}
- return 0;
+ memcpy (copy, arg, argsize);
+ return copy;
}
@@ -1047,8 +1373,6 @@ do_exec (file_t file,
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? */
@@ -1074,6 +1398,7 @@ do_exec (file_t file,
/* 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)
@@ -1083,11 +1408,30 @@ do_exec (file_t file,
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. */
+ interp.file = MACH_PORT_NULL;
/* Catch this error now, rather than later. */
/* XXX For EXEC_DEFAULTS, this is only an error if one of the user's
@@ -1135,13 +1479,11 @@ do_exec (file_t file,
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);
+ const ElfW(Phdr) *phdr = e.info.elf.phdr;
+ e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (ElfW(Phdr)));
+ check_elf_phdr (&e, phdr);
}
- interp.file = MACH_PORT_NULL;
-
if (oldtask == MACH_PORT_NULL)
flags |= EXEC_NEWTASK;
@@ -1152,6 +1494,9 @@ do_exec (file_t file,
e.error = task_create (((flags & EXEC_SECURE) ||
oldtask == MACH_PORT_NULL) ?
mach_task_self () : oldtask,
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
0, &newtask);
if (e.error)
goto out;
@@ -1178,6 +1523,7 @@ do_exec (file_t file,
if (new != MACH_PORT_NULL && reauth)
{
mach_port_t ref = mach_reply_port (), authed;
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
e.error = io_reauthenticate (new, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! e.error)
e.error = auth_user_authenticate
@@ -1209,11 +1555,6 @@ do_exec (file_t file,
}
bzero (&boot->pi + 1, (char *) &boot[1] - (char *) (&boot->pi + 1));
- /* First record some information about the image itself. */
- boot->phdr_addr = phdr_addr;
- boot->phdr_size = phdr_size;
- boot->user_entry = e.entry;
-
/* These flags say the information we pass through to the new program
may need to be modified. */
secure = (flags & EXEC_SECURE);
@@ -1225,18 +1566,18 @@ do_exec (file_t file,
boot->flags = flags;
- e.error = servercopy ((void **) &argv, argvlen, argv_copy);
+ argv = servercopy (argv, argvlen, argv_copy, &e.error);
if (e.error)
goto stdout;
boot->argv = argv;
boot->argvlen = argvlen;
- e.error = servercopy ((void **) &envp, envplen, envp_copy);
+ envp = servercopy (envp, envplen, envp_copy, &e.error);
if (e.error)
goto stdout;
boot->envp = envp;
boot->envplen = envplen;
- e.error = servercopy ((void **) &dtable, dtablesize * sizeof (mach_port_t),
- dtable_copy);
+ dtable = servercopy (dtable, dtablesize * sizeof (mach_port_t),
+ dtable_copy, &e.error);
if (e.error)
goto stdout;
boot->dtable = dtable;
@@ -1249,10 +1590,8 @@ do_exec (file_t file,
round_page (INIT_INT_MAX * sizeof (int))))
{
/* Allocate a new vector that is big enough. */
- vm_allocate (mach_task_self (),
- (vm_address_t *) &boot->intarray,
- INIT_INT_MAX * sizeof (int),
- 1);
+ 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;
}
@@ -1262,8 +1601,8 @@ do_exec (file_t file,
}
else
{
- e.error = servercopy ((void **) &intarray, nints * sizeof (int),
- intarray_copy);
+ intarray = servercopy (intarray, nints * sizeof (int), intarray_copy,
+ &e.error);
if (e.error)
goto stdout;
boot->intarray = intarray;
@@ -1276,9 +1615,8 @@ do_exec (file_t file,
/* Now choose the ports to give the new program. */
boot->nports = nports < INIT_PORT_MAX ? INIT_PORT_MAX : nports;
- vm_allocate (mach_task_self (),
- (vm_address_t *) &boot->portarray,
- boot->nports * sizeof (mach_port_t), 1);
+ 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];
@@ -1374,7 +1712,7 @@ do_exec (file_t file,
name = map (&e, (e.interp.phdr->p_offset
& ~(e.interp.phdr->p_align - 1)),
e.interp.phdr->p_filesz);
- if (! name && ! ferror (&e.stream))
+ if (! name && ! e.error)
e.error = ENOEXEC;
}
@@ -1398,8 +1736,11 @@ do_exec (file_t file,
errno = EBADF;
return MACH_PORT_NULL;
}
+ mach_port_mod_refs (mach_task_self (), boot->dtable[fd],
+ MACH_PORT_RIGHT_SEND, +1);
return boot->dtable[fd];
}
+ /* XXX/fault */
e.error = hurd_file_name_lookup (&user_port, &user_fd, 0,
name, O_READ, 0, &interp.file);
}
@@ -1421,10 +1762,10 @@ do_exec (file_t file,
else
#endif
{
- const Elf32_Phdr *phdr = interp.info.elf.phdr;
+ const ElfW(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);
+ sizeof (ElfW(Phdr)));
+ check_elf_phdr (&interp, phdr);
}
}
e.error = interp.error;
@@ -1439,7 +1780,7 @@ do_exec (file_t file,
if (newtask == oldtask)
{
- thread_array_t threads;
+ thread_t *threads;
mach_msg_type_number_t nthreads, i;
/* Terminate all the threads of the old task. */
@@ -1452,8 +1793,7 @@ do_exec (file_t file,
thread_terminate (threads[i]);
mach_port_deallocate (mach_task_self (), threads[i]);
}
- vm_deallocate (mach_task_self (),
- (vm_address_t) threads, nthreads * sizeof (thread_t));
+ munmap ((caddr_t) threads, nthreads * sizeof (thread_t));
/* Deallocate the entire virtual address space of the task. */
@@ -1500,6 +1840,20 @@ do_exec (file_t file,
/* 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. */
+ if (e.info.elf.phdr_addr != 0)
+ {
+#ifdef BFD
+ if (!e.bfd)
+#endif
+ e.info.elf.phdr_addr += e.info.elf.loadbase;
+ boot->phdr_addr = e.info.elf.phdr_addr;
+ boot->phdr_size = e.info.elf.phnum * sizeof (ElfW(Phdr));
+ }
+ boot->user_entry = e.entry; /* already adjusted in `load' */
+
/* Create the initial thread. */
e.error = thread_create (newtask, &thread);
if (e.error)
@@ -1513,6 +1867,17 @@ do_exec (file_t file,
&boot->stack_base, &boot->stack_size);
if (e.error)
goto out;
+#ifdef BFD
+ if (!e.bfd)
+#endif
+ {
+ /* It would probably be better to change mach_setup_thread so
+ it does a vm_map with the right permissions to start with. */
+ if (!e.info.elf.execstack)
+ e.error = vm_protect (newtask, boot->stack_base, boot->stack_size,
+ 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+
if (oldtask != newtask && oldtask != MACH_PORT_NULL)
{
@@ -1538,8 +1903,6 @@ do_exec (file_t file,
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. */
@@ -1566,36 +1929,53 @@ do_exec (file_t file,
authenticated anyhow. */
proc_setowner (boot->portarray[INIT_PORT_PROC],
neuids ? euids[0] : 0, !neuids);
-
+
/* Clean up */
if (euids != euidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) euids,
- neuids * sizeof (uid_t));
+ munmap (euids, neuids * sizeof (uid_t));
if (egids != egidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) egids,
- negids * sizeof (uid_t));
+ munmap (egids, negids * sizeof (uid_t));
if (auids != auidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) auids,
- nauids * sizeof (uid_t));
+ munmap (auids, nauids * sizeof (uid_t));
if (agids != agidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) agids,
- nagids * sizeof (uid_t));
+ 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);
+ mach_port_t btport = ports_get_send_right (boot);
e.error = task_set_bootstrap_port (newtask, btport);
mach_port_deallocate (mach_task_self (), btport);
}
out:
- if (e.interp.section)
+ 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
@@ -1619,7 +1999,8 @@ do_exec (file_t file,
if (thread != MACH_PORT_NULL)
{
- thread_resume (thread);
+ if (!e.error && !(flags & EXEC_SIGTRAP))
+ thread_resume (thread);
mach_port_deallocate (mach_task_self (), thread);
}
@@ -1666,13 +2047,9 @@ do_exec (file_t file,
portarray, and we are not saving those pointers in BOOT for later
transfer, deallocate the original space now. */
if (intarray_dealloc)
- vm_deallocate (mach_task_self (),
- (vm_address_t) intarray,
- nints * sizeof intarray[0]);
+ munmap (intarray, nints * sizeof intarray[0]);
if (!portarray_copy)
- vm_deallocate (mach_task_self (),
- (vm_address_t) portarray,
- nports * sizeof portarray[0]);
+ munmap (portarray, nports * sizeof portarray[0]);
}
return e.error;
@@ -1804,13 +2181,16 @@ S_exec_setexecdata (struct trivfs_protid *protid,
if (nports < INIT_PORT_MAX || nints < INIT_INT_MAX)
return EINVAL; /* */
- err = servercopy ((void **) &ports, nports * sizeof (mach_port_t),
- ports_copy);
+ err = 0;
+ ports = servercopy (ports, nports * sizeof (mach_port_t), ports_copy, &err);
if (err)
return err;
- err = servercopy ((void **) &ints, nints * sizeof (int), ints_copy);
+ ints = servercopy (ints, nints * sizeof (int), ints_copy, &err);
if (err)
- return err;
+ {
+ munmap (ports, nports * sizeof (mach_port_t));
+ return err;
+ }
rwlock_writer_lock (&std_lock);
@@ -1819,16 +2199,14 @@ S_exec_setexecdata (struct trivfs_protid *protid,
mach_msg_type_number_t i;
for (i = 0; i < std_nports; ++i)
mach_port_deallocate (mach_task_self (), std_ports[i]);
- vm_deallocate (mach_task_self (), (vm_address_t)std_ports,
- std_nports * sizeof (mach_port_t));
+ munmap (std_ports, std_nports * sizeof (mach_port_t));
}
std_ports = ports;
std_nports = nports;
if (std_ints)
- vm_deallocate (mach_task_self (), (vm_address_t)std_ints,
- std_nints * sizeof (int));
+ munmap (std_ints, std_nints * sizeof (int));
std_ints = ints;
std_nints = nints;
diff --git a/exec/execmutations.h b/exec/execmutations.h
index 62ae5c55..96b47721 100644
--- a/exec/execmutations.h
+++ b/exec/execmutations.h
@@ -4,3 +4,5 @@
#define FILE_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
#define EXEC_IMPORTS import "priv.h";
+
+#define SERVERCOPY 1
diff --git a/exec/exectrans.c b/exec/exectrans.c
deleted file mode 100644
index 59c9cdf2..00000000
--- a/exec/exectrans.c
+++ /dev/null
@@ -1,81 +0,0 @@
-
-#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_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;
-
-
-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
deleted file mode 100644
index 7343516c..00000000
--- a/exec/gcore.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* `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/hashexec.c b/exec/hashexec.c
index 748f8e1b..2aa3844b 100644
--- a/exec/hashexec.c
+++ b/exec/hashexec.c
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, #! script execution support.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -18,11 +18,11 @@ 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>
+#include <sys/param.h>
/* This is called to check E for a #! interpreter specification. E has
already been prepared (successfully) and checked (unsuccessfully). If
@@ -43,13 +43,10 @@ check_hashbang (struct execdata *e,
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;
+ size_t interp_len, arg_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;
@@ -57,12 +54,18 @@ check_hashbang (struct execdata *e,
file_t user_fd (int fd)
{
- if (fd < 0 || fd >= dtablesize || dtable[fd] == MACH_PORT_NULL)
+ if (fd >= 0 && fd < dtablesize)
{
- errno = EBADF;
- return MACH_PORT_NULL;
+ const file_t dport = dtable[fd];
+ if (dport != MACH_PORT_NULL)
+ {
+ mach_port_mod_refs (mach_task_self (), dport,
+ MACH_PORT_RIGHT_SEND, +1);
+ return dport;
+ }
}
- return dtable[fd];
+ errno = EBADF;
+ return MACH_PORT_NULL;
}
file_t user_crdir, user_cwdir;
error_t user_port (int which, error_t (*operate) (mach_port_t))
@@ -71,6 +74,9 @@ check_hashbang (struct execdata *e,
{
error_t err;
mach_port_t ref;
+
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
+
error_t uauth (auth_t auth)
{
return auth_user_authenticate (auth,
@@ -121,50 +127,81 @@ check_hashbang (struct execdata *e,
name, flags, 0, result);
}
- rewind (f);
+ const char *page;
+ char interp_buf[vm_page_size - 2 + 1];
- /* Check for our ``magic number''--"#!". */
+ e->error = 0;
+ page = map (e, 0, 2);
- errno = 0;
- if (getc (f) != '#' || getc (f) != '!')
+ if (!page)
{
- /* 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;
+ if (!e->error)
+ e->error = ENOEXEC;
return;
}
- /* Read the rest of the first line of the file. */
-
- interp_len = getline (&ibuf, &ibufsiz, f);
- if (ferror (f))
+ /* Check for our ``magic number''--"#!". */
+ if (page[0] != '#' || page[1] != '!')
{
- e->error = errno ?: EIO;
+ /* These are not the droids we're looking for. */
+ e->error = ENOEXEC;
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");
+ /* Read the rest of the first line of the file.
+ We in fact impose an arbitrary limit of about a page on this. */
- if (p)
- /* Skip remaining blanks, and the rest of the line is the argument. */
+ p = memccpy (interp_buf, page + 2, '\n',
+ MIN (map_fsize (e) - 2, sizeof interp_buf));
+ if (p == NULL)
{
- p += strspn (p, " \t");
- arg = p;
- len = interp_len - (arg - ibuf);
+ /* The first line went on for more than sizeof INTERP_BUF! */
+ interp_len = sizeof interp_buf;
+ interp_buf[interp_len - 1] = '\0';
}
else
- /* There is no argument. */
- len = 0;
+ {
+ interp_len = p - interp_buf; /* Includes null terminator. */
+ *--p = '\0'; /* Kill the newline. */
+ }
+
+ /* We are now done reading the script file. */
+ finish (e, 0);
+
+
+ /* Find the name of the interpreter. */
+ interp = interp_buf + strspn (interp_buf, " \t");
+ p = strpbrk (interp, " \t");
+
+ if (p)
+ {
+ /* Terminate the interpreter name. */
+ *p++ = '\0';
- if (len == 0)
- arg = NULL;
+ /* Skip remaining blanks, and the rest of the line is the argument. */
+
+ arg = p + strspn (p, " \t");
+ arg_len = interp_len - 1 - (arg - interp_buf); /* without null here */
+ interp_len = p - interp; /* This one includes the null. */
+
+ if (arg_len == 0)
+ arg = NULL;
+ else
+ {
+ /* Trim trailing blanks after the argument. */
+ size_t i = arg_len - 1;
+ while (arg[i] == ' ' || arg[i] == '\t')
+ arg[i--] = '\0';
+ arg_len = i + 2; /* Include the terminating null. */
+ }
+ }
else
- ++len; /* Include the terminating null. */
+ {
+ /* There is no argument. */
+ arg = NULL;
+ arg_len = 0;
+ interp_len -= interp - interp_buf; /* Account for blanks skipped. */
+ }
user_crdir = user_cwdir = MACH_PORT_NULL;
@@ -179,7 +216,7 @@ check_hashbang (struct execdata *e,
jmp_buf args_faulted;
void fault_handler (int signo)
{ longjmp (args_faulted, 1); }
- error_t setup_args (struct hurd_signal_preempter *preempter)
+ error_t setup_args (struct hurd_signal_preemptor *preemptor)
{
size_t namelen;
char * volatile file_name = NULL;
@@ -197,14 +234,13 @@ check_hashbang (struct execdata *e,
char *name;
int free_name = 0; /* True if we should free NAME. */
file_t name_file;
- mach_port_t fileid;
- dev_t filedev;
+ mach_port_t fileid, filefsid;
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_preempter *preempter)
+ error_t search_path (struct hurd_signal_preemptor *preemptor)
{
error_t err;
char *path = envz_get (envp, envplen, "PATH"), *pfxed_name;
@@ -228,9 +264,10 @@ check_hashbang (struct execdata *e,
return err;
}
- error = io_identity (file, &fileid, &filedev, &fileno);
+ error = io_identity (file, &fileid, &filefsid, &fileno);
if (error)
goto out;
+ mach_port_deallocate (mach_task_self (), filefsid);
if (memchr (argv, '\0', argvlen) == NULL)
{
@@ -251,11 +288,15 @@ check_hashbang (struct execdata *e,
if (!error && name_file != MACH_PORT_NULL)
{
- mach_port_t id;
- dev_t dev;
+ mach_port_t id, fsid;
ino_t ino;
- error = io_identity (name_file, &id, &dev, &ino);
- __mach_port_deallocate (__mach_task_self (), id);
+ error = io_identity (name_file, &id, &fsid, &ino);
+ mach_port_deallocate (mach_task_self (), name_file);
+ if (!error)
+ {
+ mach_port_deallocate (mach_task_self (), fsid);
+ mach_port_deallocate (mach_task_self (), id);
+ }
if (!error && id == fileid)
{
file_name = name;
@@ -263,10 +304,9 @@ check_hashbang (struct execdata *e,
}
else if (free_name)
free (name);
- __mach_port_deallocate (__mach_task_self (), name_file);
}
- __mach_port_deallocate (__mach_task_self (), fileid);
+ mach_port_deallocate (mach_task_self (), fileid);
}
if (file_name == NULL)
@@ -298,33 +338,50 @@ check_hashbang (struct execdata *e,
/* Prepare the arguments to pass to the interpreter from the original
arguments and the name of the script file. The args will look
- like `ARGV[0] {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
+ like `INTERP {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
omitted). */
namelen = strlen (file_name) + 1;
- new_argvlen = argvlen + len + namelen;
- e->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &new_argv,
- new_argvlen, 1);
- if (e->error)
- return e->error;
+ new_argvlen
+ = (argvlen - strlen (argv) - 1) /* existing args - old argv[0] */
+ + interp_len + arg_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;
- other_args = memccpy (new_argv, argv, '\0', argvlen);
- p = &new_argv[other_args ? other_args - new_argv : argvlen];
+
+ p = new_argv;
+
+ /* INTERP */
+ memcpy (p, interp, interp_len);
+ p += interp_len;
+
+ /* Maybe ARG */
if (arg)
{
- memcpy (p, arg, len);
- p += len;
+ memcpy (p, arg, arg_len);
+ p += arg_len;
}
+
+ /* FILE_NAME */
memcpy (p, file_name, namelen);
p += namelen;
- if (other_args)
- memcpy (p, other_args - new_argv + argv,
- argvlen - (other_args - new_argv));
+
+ /* Maybe remaining args */
+ other_args = argv + strlen (argv) + 1;
+ if (other_args - argv < argvlen)
+ memcpy (p, other_args, argvlen - (other_args - argv));
}
else
{
@@ -332,7 +389,7 @@ check_hashbang (struct execdata *e,
char *n = stpncpy (new_argv,
"**fault in exec server reading argv[0]**",
argvlen);
- memcpy (memcpy (n, arg, len) + len, file_name, namelen);
+ memcpy (memcpy (n, arg, arg_len) + arg_len, file_name, namelen);
}
if (free_file_name)
@@ -347,10 +404,6 @@ check_hashbang (struct execdata *e,
&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)
@@ -384,21 +437,19 @@ check_hashbang (struct execdata *e,
task_resume (oldtask); /* Our caller suspended it. */
mach_port_deallocate (mach_task_self (), oldtask);
if (! argv_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) argv, argvlen);
+ munmap (argv, argvlen);
if (! envp_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) envp, envplen);
+ munmap (envp, envplen);
for (i = 0; i < dtablesize; ++i)
- mach_port_deallocate (mach_task_self (), dtable[i]);
+ if (MACH_PORT_VALID (dtable[i]))
+ mach_port_deallocate (mach_task_self (), dtable[i]);
if (! dtable_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) dtable,
- dtablesize * sizeof *dtable);
+ munmap (dtable, dtablesize * sizeof *dtable);
for (i = 0; i < nports; ++i)
mach_port_deallocate (mach_task_self (), portarray[i]);
if (! portarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) portarray,
- nports * sizeof *portarray);
+ munmap (portarray, nports * sizeof *portarray);
if (! intarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) intarray,
- nints * sizeof *intarray);
+ munmap (intarray, nints * sizeof *intarray);
}
}
diff --git a/exec/hostarch.c b/exec/hostarch.c
index 38a38a00..ec59a417 100644
--- a/exec/hostarch.c
+++ b/exec/hostarch.c
@@ -1,6 +1,6 @@
/* 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 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,95,96,99,2000,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -10,7 +10,7 @@ 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,
+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.
@@ -19,17 +19,82 @@ 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 <bfd.h>
#include <elf.h>
error_t
+elf_machine_matches_host (ElfW(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:
+ case CPU_TYPE_I486:
+ case CPU_TYPE_PENTIUM:
+ case CPU_TYPE_PENTIUMPRO:
+ CACHE (e_machine == EM_386);
+
+ 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,
- Elf32_Half *e_machine)
+ long int *machine)
{
error_t err;
struct host_basic_info hostinfo;
@@ -117,3 +182,5 @@ bfd_mach_host_arch_mach (host_t host,
return 0;
}
+
+#endif /* BFD */
diff --git a/exec/main.c b/exec/main.c
index 809b99a8..efad85aa 100644
--- a/exec/main.c
+++ b/exec/main.c
@@ -1,46 +1,48 @@
/* GNU Hurd standard exec server, main program and server mechanics.
- Copyright (C) 1992, 1993, 19941996 Free Software Foundation, Inc.
- Written by Roland McGrath.
-This file is part of the GNU Hurd.
+ Copyright (C) 1992,93,94,95,96,97,98,99,2000,01,02
+ 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 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.
+ 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. */
+ 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 (exec);
+#ifdef BFD
bfd_arch_info_type host_bfd_arch_info;
bfd host_bfd = { arch_info: &host_bfd_arch_info };
-Elf32_Half elf_machine; /* ELF e_machine for the host. */
-
extern error_t bfd_mach_host_arch_mach (host_t host,
enum bfd_architecture *bfd_arch,
long int *bfd_machine,
- Elf32_Half *elf_machine);
-
+ ElfW(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;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_allow_open = 0;
struct port_class *trivfs_protid_portclasses[1];
struct port_class *trivfs_cntl_portclasses[1];
@@ -49,7 +51,6 @@ int trivfs_cntl_nportclasses = 1;
struct trivfs_control *fsys;
-char *exec_version = "0.0";
char **save_argv;
@@ -72,21 +73,15 @@ deadboot (void *p)
struct bootinfo *boot = p;
size_t i;
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->argv, boot->argvlen);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->envp, boot->envplen);
+ 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]);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->portarray,
- boot->nports * sizeof (mach_port_t));
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->intarray,
- boot->nints * sizeof (int));
+ 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)
@@ -113,17 +108,21 @@ 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,
- &elf_machine);
+ &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)
@@ -150,8 +149,7 @@ main (int argc, char **argv)
/* Launch. */
ports_manage_port_operations_multithread (port_bucket, exec_demuxer,
- 2 * 60 * 1000, 0,
- 0, MACH_PORT_NULL);
+ 2 * 60 * 1000, 0, 0);
return 0;
}
@@ -204,24 +202,6 @@ trivfs_goaway (struct trivfs_control *fsys, int flags)
}
}
-/* Attempt to set the active translator for the exec server so that
- filesystems other than the bootstrap can find it. */
-void
-set_active_trans ()
-{
- file_t execnode;
-
- execnode = file_name_lookup (_SERVERS_EXEC, O_NOTRANS | O_CREAT, 0666);
- if (execnode == MACH_PORT_NULL)
- return;
-
- file_set_translator (execnode, 0, FS_TRANS_SET, 0, 0, 0,
- ports_get_right (fsys), MACH_MSG_TYPE_MAKE_SEND);
- /* Don't deallocate EXECNODE here. If we drop the last reference,
- a bug in ufs might throw away the active translator. XXX */
-}
-
-
/* Sent by the bootstrap filesystem after the other essential
servers have been started up. */
@@ -229,7 +209,7 @@ kern_return_t
S_exec_init (struct trivfs_protid *protid,
auth_t auth, process_t proc)
{
- mach_port_t host_priv, dev_master, startup;
+ mach_port_t host_priv, startup;
error_t err;
if (! protid || ! protid->isroot)
@@ -239,50 +219,45 @@ S_exec_init (struct trivfs_protid *protid,
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], auth); /* Consume. */
/* Do initial setup with the proc server. */
- _hurd_proc_init (save_argv);
-
- /* Set the active translator on /servers/exec. */
- set_active_trans ();
+ _hurd_proc_init (save_argv, NULL, 0);
procserver = getproc ();
- err = get_privileged_ports (&host_priv, &dev_master);
- if (!err)
- {
- proc_register_version (procserver, host_priv, "exec", HURD_RELEASE,
- exec_version);
- mach_port_deallocate (mach_task_self (), dev_master);
- err = proc_getmsgport (procserver, 1, &startup);
- if (err)
- {
- mach_port_deallocate (mach_task_self (), host_priv);
- host_priv = MACH_PORT_NULL;
- }
- }
- else
- host_priv = MACH_PORT_NULL;
-
+ /* 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. */
{
- /* Have the proc server notify us when the canonical ints and ports
- change. */
-
+ struct iouser *user;
struct trivfs_protid *cred;
- err = trivfs_open (fsys, 0, 0, 0, 0, 0, MACH_PORT_NULL, &cred);
+ mach_port_t right;
+
+ err = iohelp_create_empty_iouser (&user);
+ assert_perror (err);
+ err = trivfs_open (fsys, user, 0, MACH_PORT_NULL, &cred);
assert_perror (err);
- proc_execdata_notify (procserver, ports_get_right (cred),
- MACH_MSG_TYPE_MAKE_SEND);
+ right = ports_get_send_right (cred);
+ proc_execdata_notify (procserver, right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
}
+ 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. */
- if (host_priv != MACH_PORT_NULL)
- {
- startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
- "exec", host_priv);
- mach_port_deallocate (mach_task_self (), startup);
- mach_port_deallocate (mach_task_self (), host_priv);
- }
+ 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
index 0ded21eb..7cee15e4 100644
--- a/exec/priv.h
+++ b/exec/priv.h
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, private declarations.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2000,02, 04 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@ 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,
+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.
@@ -22,12 +22,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#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 <link.h> /* This gives us the ElfW macro. */
#include <fcntl.h>
#include "exec_S.h"
@@ -35,11 +41,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#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;
-extern Elf32_Half elf_machine; /* ELF e_machine for the host. */
-
+#endif
/* Information kept around to be given to a new task
in response to a message on the task's bootstrap port. */
@@ -62,11 +68,14 @@ struct bootinfo
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. */
+#ifdef BFD
+#define EXECDATA_STREAM /* BFD uses stdio to access the executable. */
+#else
+typedef void asection;
+#endif
+
/* Data shared between check, check_section,
load, load_section, and finish. */
@@ -77,16 +86,46 @@ struct execdata
/* Set by check. */
vm_address_t entry;
- FILE stream;
file_t file;
+#ifndef EXECDATA_STREAM
+
+ /* Note that if `file_data' (below) is set, then these just point
+ into that and should not be deallocated (file_data is malloc'd). */
+ char *map_buffer; /* Our mapping window or read buffer. */
+ size_t map_vsize; /* Page-aligned size allocated there. */
+ size_t map_fsize; /* Bytes from there to end of mapped data. */
+ off_t map_filepos; /* Position `map_buffer' maps to. */
+#define map_buffer(e) ((e)->map_buffer)
+#define map_fsize(e) ((e)->map_fsize)
+#define map_vsize(e) ((e)->map_vsize)
+#define map_filepos(e) ((e)->map_filepos)
+#define map_set_fsize(e, fsize) ((e)->map_fsize = (fsize))
+
+#else
+
+#ifdef _STDIO_USES_IOSTREAM
+# error implement me for libio!
+#else
+ FILE stream;
+#define map_buffer(e) ((e)->stream.__buffer)
+#define map_fsize(e) ((e)->stream.__get_limit - (e)->stream.__buffer)
+#define map_vsize(e) ((e)->stream.__bufsize)
+#define map_filepos(e) ((e)->stream.__offset)
+#define map_set_fsize(e, fsize) \
+ ((e)->stream.__get_limit = (e)->stream.__buffer + (fsize))
+#endif
+
+#endif
+
#ifdef BFD
bfd *bfd;
#endif
+
union /* Interpreter section giving name of file. */
{
asection *section;
- const Elf32_Phdr *phdr;
+ const ElfW(Phdr) *phdr;
} interp;
memory_object_t filemap, cntlmap;
struct shared_io *cntl;
@@ -108,16 +147,26 @@ struct execdata
/* 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. */
+ ElfW(Phdr) *phdr;
+ ElfW(Addr) phdr_addr;
+ ElfW(Word) phnum; /* Number of program header table elements. */
int anywhere; /* Nonzero if image can go anywhere. */
vm_address_t loadbase; /* Actual mapping location. */
+ int execstack; /* Zero if stack can be nonexecutable. */
} elf;
} info;
};
+error_t elf_machine_matches_host (ElfW(Half) e_machine);
+
void finish (struct execdata *, int dealloc_file_port);
+/* Make sure our mapping window (or read buffer) covers
+ LEN bytes of the file starting at POSN, and return
+ a pointer into the window corresponding to POSN. */
+void *map (struct execdata *e, off_t posn, size_t len);
+
+
void check_hashbang (struct execdata *e,
file_t file,
task_t oldtask,