diff options
Diffstat (limited to 'debian')
59 files changed, 12220 insertions, 0 deletions
diff --git a/debian/NEWS b/debian/NEWS new file mode 100644 index 00000000..c879f796 --- /dev/null +++ b/debian/NEWS @@ -0,0 +1,22 @@ +hurd (20050513-4) unstable; urgency=low + + * The Hurd console may now be started automatically on bootup. The + file `/etc/default/hurd-console' controls whether the Hurd console + will be started, and if so, which options are used. To get the + Hurd console on bootup, change ENABLE to `true' and adjust the + other options to your liking. + + -- Michael Banck <mbanck@debian.org> Sun, 28 Aug 2005 14:43:31 +0200 + +hurd (20050119-1) unstable; urgency=low + + * The command line syntax for the console client has slightly + changed. It is no longer necessary or even allowed to specify the + consnode path to the short `-c' option (e.g. `-c /dev/cons'), + /dev/cons is implied as default (but can be changed using the long + option, `--consnode=FOO'). When using the mouse or keyboard + repeater, the console client command line should now be as follows: + console -d vga -d pc_kbd --repeat=kbd -d pc_mouse --repeat=mouse \ + -d generic_speaker -c /dev/vcs + + -- Michael Banck <mbanck@debian.org> Fri, 21 Jan 2005 02:33:36 +0100 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..012087be --- /dev/null +++ b/debian/changelog @@ -0,0 +1,1015 @@ +hurd (20090404.1-1) UNRELEASED; urgency=low + + [ Samuel Thibault ] + * Cleaned upstream 20090404 snapshot. + * debian/rules: Really put debugging symbols into the hurd-dbg package. + * debian/patches/libpthread_cancel_init.patch: New patch to fix portability + of pthread.h + * debian/patches/libpthread_kill_0.patch: New patch to fix pthread_kill(th, + 0); + * debian/patches/console_current_vcs.patch: Cherry-pick patch to fix + loading the current_vcs driver. + * debian/patches/hurd_console_startup.patch: Add -d current_vcs to enable + /dev/cons/vcs by default. + * debian/copyright: Reference /usr/share/common-licenses/GPL-2 instead of + just GPL. + * debian/hurd.dirs: Add /etc/sysctl.d. + * debian/control (hurd-udeb): Add Provides: *-modules. + * debian/patches/diskfs_no_inherit_dir_group.patch: Fix documentation too. + * debian/control: + - Drop duplicate priority and section fields. + - Add ${misc:Depends}. + - Add dpkg (>= 1.15.4) | install-info dependency. + - Drop -1 from gnumach-dev dependency. + - Bump Standards-Version to 3.8.4 (no change needed). + * debian/local/runsystem.gnu: New runsystem file for the d-i case, incomplete + for now. + * debian/hurd-udeb.install: Remove getty, runttys, /etc/ttys ftpcp, ftpdir, + ftpfs, hostmux, usermux, nfs, isofs.static, rpctrace, gcore, forks. Install + local/runsystem.gnu in /libexec, install ext2fs.static in /boot + * debian/rules: Do not ship *_pic.a, as mklibs breaks them. + * debian/patches/MAKEDEV.patch: Make MAKEDEV bash-free. + * debian/patches/tmpfs.patch: New patch to fix tmpfs crash. + * debian/patches/proxy-defpager.diff: New patch to fix proxying defpager. + * debian/patches/ext2fs_large_stores.patch: Apply Alioth fix #312328 from + Fredrik Hammar to fix random startup crash (Closes: Bug#576519). + * debian/patches/procfs.patch: Fix swap size printout. + * debian/hurd-udeb.install: remove reboot and halt (will be provided by + busybox), remove crash and password (not useful), add procfs, remove rc. + * debian/local/runsystem.gnu: Integrate jkoenig d-i changes, rename to + debian/local/runsystem. + + [ Guillem Jover ] + * Update make-new-tarball.sh to exclude git instead of CVS paths. + * Refresh patches with -pab to allow migration to source format 3.0 (quilt). + * Switch to source format “3.0 (quilt)”: + - Remove quilt from Build-Depends. + - Remove patchsys-quilt.mk include from debian/rules. + + [ Michael Banck ] + * debian/control (Uploaders): Removed Marcus Brinkmann. (Closes: #503564) + + -- Samuel Thibault <sthibault@debian.org> Tue, 13 Oct 2009 01:20:44 +0200 + +hurd (20090404-2) unstable; urgency=low + + * debian/patches/libpthread_no_recursive_mutex_initializer.patch: Remove + unused patch. + * debian/patches/procfs.patch: Fix a couple of memory leaks, fix swap size + report. + * debian/control: Add missing comma in Build-Depends. + * debian/patches/pfinet-gcc-4.3-fix.patch: Cherry-pick upstream patch to fix + build with gcc-4.3 + * debian/rules: Set CC to gcc-4.3 instead of gcc-4.2. + * debian/control: Build-Depend on gcc-4.3 instead of gcc-4.2. + (Closes: Bug#533782) + * debian/control: Add Provides: hurd to the hurd-udeb package, to meet + dependencies. + * debian/rules: Add --add-udeb="hurd-udeb" option to dh_makeshlibs + invocation for the hurd package, to fix udeb dependency generation. + * debian/patches/MAKEDEV.patch: New patch to use bash for MAKEDEV. + (Closes: Bug#548587) + * debian/patches/libdiskfs-rename.patch: New patch to fix ext2fs hang on + renaming directory to something/. + + -- Samuel Thibault <sthibault@debian.org> Sun, 11 Oct 2009 04:38:02 +0200 + +hurd (20090404-1) unstable; urgency=low + + [ Michael Banck ] + * New snapshot from CVS. + + debian/patches/diskfs_lookup_error_fix.patch: Removed, applied upstream. + + debian/patches/libpthread_mutex-no-include.patch: Likewise. + + debian/patches/libpthread_pthreadtypes_h.patch: Likewise. + + debian/patches/libpthread_spin-lock-inline.patch: Likewise. + + debian/patches/lock-memory-clobber.patch: Likewise. + + debian/patches/pflocal-port-leak.patch: Likewise. + + debian/patches/libpthread_pthreadexit-safety.patch: Removed, no longer + needed. + + debian/patches/libpthread_tls.patch: Refreshed. + * Change packaging to no tarball-in-tarball and quilt. + + debian/control (Build-Depends): Added quilt. + + debian/rules (DEB_TAR_SRCDIR): Removed. + + debian/rules (tarball.mk) No longer include it. + + debian/rules (simple-patchsys.mk) Replaced with ... + + debian/rules (patchsys-quilt.mk) ... this. + + debian/patches/series: New file. + + debian/rules (build/hurd): Replace build-tree with $(DEB_SRCDIR). + + debian/rules (install/hurd): Likewise. + + debian/hurd-doc.docs: Adjust paths. + * debian/hurd.postinst: Install ps alternatives link in /bin, not + /usr/bin. + * debian/hurd.postinst: Install /proc as passive translator only. + * debian/patches/uptime_w_path_fix.patch: New patch, run /usr/bin/w instead + of /bin/w. + * debian/rules: Install fakeroot, uptime and vmstat into /usr/bin, not /bin. + * debian/rules (binary-predeb/hurd): Adjust paths. + * debian/hurd.install: Likewise. + * debian/hurd-udeb.install: Likewise. + * debian/hurd.dirs: Added /usr/bin. + * debian/hurd.postinst: Update accordingly. + * debian/patches/libpthread_mutex_owner.patch: New patch, fix a hang in + libpthread, by Neal Walfield. + + [ Samuel Thibault ] + * debian/patches/thread-throttle.patch: Remove patch, makes ext2fs hang on + big syncs. + * debian/control (Build-Depends): Bump libc0.3-dev to (>= 2.9). + * debian/patches/stat_round.patch: New temporary patch, fixes symlink issues + with tar. + * debian/patches/dir_acces_fix.patch: New patch, fixes ext2fs crashes. + * debian/patches/libports_stability.patch: New patch to keep the old + behavior of libports. + * debian/patches/libpthread_fix.patch: New patch from Thomas Schwinge to fix + libpthread. + * debian/patches/libpthread_setcancel.patch: New patch to fix configuration + of octave3.0. + * debian/patches/extern_inline_fix.patch: New patch from Marc Dequène to + fix extern inline declarations. + * debian/patches/exec_fix.patch: New patch to fix random hang of exec. + * debian/patches/libpthread_recursive_mutex_initializer.patch: New patch + to fix the recursive mutex initializers usage in libraries not linking + against libpthread. + * debian/control: Now using Standards-Version 3.8.2 (no changes needed). + * debian/control: Add myself to uploaders. + + [ Guillem Jover ] + * Change hurd-dbg section to debug. + + -- Samuel Thibault <sthibault@debian.org> Sun, 28 Jun 2009 22:19:07 +0000 + +hurd (20080607-6) unstable; urgency=low + + * debian/rules (install/hurd): Move away ps, uptime, vmstat and w in order + to have them handled by update-alternatives. + * debian/hurd.install: Update accordingly. + * debian/hurd-udev.install: Likewise. + * debian/rules (SUID_PROGRAMS): Likewise. + * debian/hurd.postinst: Run update-alternatives for ps, uptime, vmstat and + w. + * debian/hurd.postinst: Setup /proc if it hasn't been already. + + -- Michael Banck <mbanck@debian.org> Fri, 12 Sep 2008 22:58:08 +0200 + +hurd (20080607-5) unstable; urgency=low + + * debian/patches/procfs.patch: New patch, implements a /proc translator, by + Madhusudan C.S., taken from a CVS branch. + + -- Michael Banck <mbanck@debian.org> Tue, 02 Sep 2008 00:24:36 +0200 + +hurd (20080607-4) unstable; urgency=low + + [ Samuel Thibault ] + * debian/patches/pflocal-port-leak.patch: New patch to fix port leaks in + pflocal which was making tcl-related builds hang. + * debian/patches/lock-memory-clobber.patch: New patch to fix lock safety. + * debian/patches/libpthread_mutex-no-include.patch: New patch to drop + useless (and problematic) inclusion from mutex.h. + * debian/patches/libpthread_spin-lock-inline.patch: New patch to split off + inlines from spin-lock.h into spin-lock-inline.h to avoid including too + many headers from pthreadtypes.h (fixes glibc 2.7-13 compilation). + * debian/patches/libpthread_pthreadtypes_h.patch: Remove comma at end of + enumeration. + * debian/patches/diskfs_lookup_error_fix.patch: New patch to fix deadlock in + lookup error conditions. + + -- Michael Banck <mbanck@debian.org> Fri, 29 Aug 2008 22:53:20 +0200 + +hurd (20080607-3) unstable; urgency=low + + [ Samuel Thibault ] + * debian/patches/libpthread_pthreadtypes_h.patch: fix patch into really + installing <pthread/pthreadtypes.h>. + + -- Michael Banck <mbanck@debian.org> Sat, 12 Jul 2008 02:23:21 +0200 + +hurd (20080607-2) unstable; urgency=low + + [ Samuel Thibault ] + * debian/patches/libpthread_pthreadtypes_h.patch: New patch to get pthread + types into <pthread/pthreadtypes.h>, which <bits/pthreadtypes.h> will be + able to include. + * debian/patches/libpthread_stubs.patch: Fix build. + * debian/patches/libpthread_pthreadexit-safety.patch: New patch to fix a + race during thread exit. Fixes e.g. libatomic-ops' testsuite, and + probably also a lot of others'. + + -- Michael Banck <mbanck@debian.org> Fri, 11 Jul 2008 15:33:27 +0200 + +hurd (20080607-1) unstable; urgency=low + + * New snapshot from CVS. + + debian/patches/ext2fs_large_stores.patch: Removed copyright year + changes. + + debian/patches/libpthread_getattr.patch: Removed, applied upstream. + + debian/patches/libpthread_inline.patch: Likewise. + + debian/patches/mmx.patch: Likewise. + + debian/patches/libpthread_stubs.patch: Updated, one hunk got applied + upstream. + * debian/rules (CC): New variable, set to gcc-4.2. + * debian/control (Build-Depends): Added gcc-4.2. + + -- Michael Banck <mbanck@debian.org> Wed, 11 Jun 2008 01:02:01 +0200 + +hurd (20071119-2) unstable; urgency=low + + [ Michael Banck ] + * debian/local/menu.lst: Add some comments. + * debian/patches/libpthread_getattr.patch: New patch, implements + pthread_getattr_np, taken from CVS. + + [ Guillem Jover ] + * debian/copyright: Update FSF address. + * debian/control: Use binary:Version and source:Version instead of + deprecated Source-Version substvar. + * debian/changelog: Fix Neal's mail address in ancient entry. + * debian/control: Line-wrap Build-Depends and Uploaders fields. + * debian/control: Now using Standards-Version 3.7.3 (no changes needed). + * debian/control: Move packages from base Section to admin. + * debian/control: Add Homepage field. + * debian/control: Add Vcs-Browser and Vcs-Svn fields. + + [ Samuel Thibault] + * debian/patches/mmx.patch: New patch to align the stack of created + threads. + * debian/patches/thread-throttle.patch: New patch, add a fix for ext2fs to + keep the superblock in memory so as to avoid a thread creation dead lock. + * debian/patches/libpthread_stubs.diff: New patch, add generation of + <gnu/stubs-pthread.h> to advertise libpthread stubs. + + -- Michael Banck <mbanck@debian.org> Sun, 18 May 2008 20:22:32 +0200 + +hurd (20071119-1) unstable; urgency=low + + * New snapshot from CVS. + + Includes a port of Linux' IPv6 support by Stefan Siegl. + (Closes: #274156) + + debian/patches/glibc_stat_updates.patch: Removed, applied upstream. + + debian/patches/libpthread_no-inline.patch: Likewise. + + debian/patches/pfinet_-fno-strict-aliasing.patch: Likewise. + + debian/patches/servers.boot-update.patch: Likewise. + + debian/patches/siocgifhwaddr.patch: Likewise. + + debian/patches/pfinet_dhcp.patch: Rediffed. + + debian/patches/pflocal.patch: Likewise. + + [ Samuel Thibault ] + * debian/local/soundcard.h: Add _PATCHKEY definition. + * debian/patches/libpthread_tls.patch: New patch, replaces + debian/patches/libpthread_tls_transitional.patch. + * debian/patches/libpthread_inline.patch: New patch to fix extern inlines + with gcc 4.3. + + [ Michael Banck ] + * debian/patches/runsystem_setup_pflocal.patch: New patch, sets up + pflocal during bootup if this has not been done before (in the install + case). + * debian/hurd.dirs: Added servers/socket. + * debian/patches/init_try_runsystem.gnu.patch: New patch, try + /libexec/runsystem.gnu as well if /libexec/runsystem is not + available. + * debian/patches/tmp_exec_startup.patch: New patch, try to attach the + exec server to /tmp/exec if /servers/exec is not yet available. + * debian/patches/diskfs_no_inherit_dir_group.patch: Update with better + patch by Thomas Schwinge. + * debian/patches/pfinet_dhcp.patch: Updated with new patch by Christian + Dietrich and Stefan Siegl. + * debian/local/menu.lst: New file. + * debian/hurd.examples: Ship it. + + -- Michael Banck <mbanck@debian.org> Tue, 08 Jan 2008 01:10:07 +0100 + +hurd (20070606-3) unstable; urgency=low + + [ Michael Banck ] + * debian/patches/patches/servers.boot-update.patch: New patch, updates + the servers.boot script to use the currently used Grub module lines. + * debian/rules (install/hurd::): Install release/servers.boot into /boot. + * debian/patches/pfinet_-fno-strict-aliasing.patch: New patch, adding + -fno-strict-aliasing to pfinet's CFLAGS to fix compilation with gcc-4.2, + taken from CVS. + * debian/hurd.dirs: Added /boot. + + [ Samuel Thibault ] + * debian/patches/patches/libpthread_no-inline.patch: New patch, removes + extern inlines to fix g++ and gettext FTBFS, by Samuel Thibault. + + -- Michael Banck <mbanck@debian.org> Thu, 9 Aug 2007 17:08:01 +0200 + +hurd (20070606-2) unstable; urgency=low + + * debian/patches/libpthread_tls_transitional.patch: New patch, + implements TLS for libpthread, by Samuel Thibault. + * debian/patches/libpthread_weak_inline.patch: Removed. + + -- Michael Banck <mbanck@debian.org> Sun, 22 Jul 2007 23:45:39 +0200 + +hurd (20070606-1) unstable; urgency=low + + * New snapshot from CVS. + + Includes a patch to make pthread_* function aliases strong. + (Closes: #407208) + + debian/patches/console_ioperms.patch: Removed, fixed upstream. + + debian/patches/no-debian-dir.patch: Removed, applied upstream. + * debian/local/soundcard.h: Updated by Samuel Thibault. + * debian/control (Build-Depends): Added libc0.3-dev (>= 2.5-5). + * debian/copyright: Clarify that the package is maintained by the + Debian GNU Hurd maintainers and no longer by upstream. + * debian/control (Build-Depends): Bumped gnumach-dev version to + 2:1.3.99.dfsg.cvs20070526-1. + * debian/control (hurd/Depends): Bumped gnumach version to + 2:1.3.99.dfsg.cvs20070526-1. + + -- Michael Banck <mbanck@debian.org> Wed, 6 Jun 2007 18:54:37 +0200 + +hurd (20060825-2) unstable; urgency=low + + * Rebuilt against gnumach_1:20060826.dfsg.1-1. + * debian/control (hurd/Depends): Bump versioned dependency of gnumach + to 1:20060826.dfsg.1-1. + * debian/control (Build-Depends): Added versioned Build-Depends on + gnumach-dev 1:20060826.dfsg.1-1. + * debian/control (Build-Depends-Indep): Moved texi2html to ... + * debian/control (Build-Depends): ... here. + + -- Michael Banck <mbanck@debian.org> Wed, 30 Aug 2006 00:17:15 +0200 + +hurd (20060825-1) unstable; urgency=low + + * New snapshot from CVS. + * debian/patches/beta_make.patch: Removed, fixed upstream. + * debian/patches/ext2fs_large_stores.patch: Resynced. + * debian/patches/pfinet_dhcp.patch: Likewise. + * debian/patches/ftpfs_fix.patch: Removed, applied upstream. + * debian/patches/gcc-4.0_fixes.patch: Likewise. + * debian/patches/libpthread_need_clockid_t.patch: Likewise. + * debian/patches/libstore_attribute.patch: Likewise. + * debian/patches/magic_port_leak.patch: Likewise. + * debian/patches/pfinet_packet_filter.diff: Likewise. + * debian/patches/semaphore_restrict_fix.patch: Likewise. + * debian/rules (build/hurd::): Assemble all upstream ChangeLogs to one + big ChangeLog. + * debian/rules (DEB_INSTALL_CHANGELOGS_ALL): New variable, install it. + * debian/patches/no_shm_makedev.diff: Renamed to ... + * debian/patches/makedev.diff: ... this. + * debian/patches/console_utf-8.patch: New patch, setting the Hurd + console to UTF-8 by default. (Closes: #348260) + + -- Michael Banck <mbanck@debian.org> Sat, 26 Aug 2006 01:00:41 +0200 + +hurd (20050513-8) unstable; urgency=low + + * debian/patches/pfinet_packet_filter: New patch, adding support for + gathering incoming packets, taken from CVS. + * debian/hurd.install: Install hurd.msgids into /usr/share/msgids. + * debian/hurd.dirs: Added /usr/share/msgids. + * debian/patches/sysvshm.patch: Removed, it was causing deadlocks. + + -- Michael Banck <mbanck@debian.org> Fri, 4 Aug 2006 15:54:09 +0200 + +hurd (20050513-7) unstable; urgency=low + + * debian/patches/diskfs_no_inherit_dir_group.patch: New patch, + enabling SysV style behaviour (i.e. adopt the user's gid, not the + one from the parent directory) for group permissions of newly + created files by default. + * debian/rules (install/hurd::): Install motd.UTF8 into /etc. + * debian/patches/install-msgids.diff: New patch, install RPC message + IDs in $(datadir)/msgids, by Alfred M. Szmidt. + * debian/hurd.postinst: Create symlinks for /dev/kbd and /dev/mouse to + /dev/cons/{kbd,mouse} if not present already. (Closes: #355002) + * debian/patches/no_shm_makedev.diff: New patch, skip /dev/shm device + when generating the standard devices. + * debian/hurd.postinst: Create /dev/shm directory if not present + already. + * debian/patches/ext2fs_large_stores.patch: Include <hurd/pager.h> + rather than "../libpager/pager.h" and add pager to libdiskfs' + HURDLIBS. + * local/soundcard.h: New file by Samuel Thibault. + * debian/rules (install/hurd-dev::) New rule, install soundcard.h + in debian/tmp/include/sys. + + -- Michael Banck <mbanck@debian.org> Tue, 25 Apr 2006 19:30:33 +0200 + +hurd (20050513-6) unstable; urgency=low + + * debian/patches/console_ioperms.patch: New patch by Samuel Thibault. + * debian/control (hurd): Add versioned Depends on gnumach 1:20050801-3. + * debian/patches/beta_make.patch: New patch, support newer make. + + -- Michael Banck <mbanck@debian.org> Thu, 12 Jan 2006 02:42:36 +0100 + +hurd (20050513-5) unstable; urgency=low + + * debian/patches/thread-throttle.patch: New patch by Sergio Lopez. + * debian/patches/gcc-4.0_fixes.patch: New patch by Thomas Schwinge. + * debian/patches/libstore_attribute.patch: New patch by Roland + McGrath, taken from CVS. + * debian/rules (CC): Removed. + * debian/control (Build-Depends): Removed gcc-3.3. + * debian/patches/libpthread_weak_inline.patch: New patch by Neal + Walfield. + + -- Michael Banck <mbanck@debian.org> Sun, 11 Dec 2005 13:31:11 +0100 + +hurd (20050513-4) unstable; urgency=low + + * debian/rules (DEB_CONFIGURE_USER_FLAGS): Build iso9660fs.static + as well. + * debian/hurd-udeb.install: Added iso9660fs.static. + * debian/patches/hurd_console_startup.patch: New patch, adding + support for starting the Hurd console on bootup. + * debian/hurd.dirs: Added `etc/default'. + * debian/hurd-console.default: New file. + * debian/rules (install/hurd::) Install it into debian/hurd/etc/default. + * debian/hurd.postinst: Removed creation of user `login'. + * debian/NEWS: Mention the possibility of starting the Hurd console + on bootup. + * debian/patches/magic_port_leak.patch: New patch by Marcus + Brinkmann, taken from CVS. + * debian/patches/ftpfs_fix.patch: New patch by Samuel Thibault. + * debian/patches/sysvshm.patch: New patch by Marcus Brinkmann. + * debian/patches/libpager_update_seqno.patch: New patch by Sergio Lopez. + * debian/patches/semaphore_restrict_fix.patch: New patch by Samuel + Thibault. (Closes: #320121) + * debian/control (Build-Depends): Added gcc-3.3. + * debian/rules (CC): New variable, set to gcc-3.3. + + -- Michael Banck <mbanck@debian.org> Sun, 28 Aug 2005 14:45:55 +0200 + +hurd (20050513-3) unstable; urgency=low + + * debian/control (hurd-doc): Fix description to indicate the manual + is included in HTML and not PostScript format. (Closes: #309748) + * debian/control (hurd-dev): Provide/Replace/Conflict libsem-dev. + * debian/control (Build-Depends): Version dependency on debhelper to + >= 4.2. + * debian/control (hurd-udeb): New package. + * debian/hurd-udeb.install: New file. + * debian/patches/libpthread_need_clockid_t.patch: Updated from CVS. + + -- Michael Banck <mbanck@debian.org> Thu, 9 Jun 2005 01:40:31 +0200 + +hurd (20050513-2) unstable; urgency=low + + * debian/patches/libpthread_need_clockid_t.patch: New patch by Neal + Walfield. + * debian/patches/pflocal.patch: New patch by Neal Walfield. + + -- Michael Banck <mbanck@debian.org> Tue, 17 May 2005 18:37:08 +0200 + +hurd (20050513-1) unstable; urgency=low + + * New snapshot from CVS. + + Contains a POSIX semaphore implementation by Neal Walfield. + + Contains more libpthread fixes for test suites by Neal Walfield. + * debian/hurd.postinst: Handle /bin/fakeroot-hurd by alternatives. + + -- Michael Banck <mbanck@debian.org> Sun, 15 May 2005 13:00:12 +0200 + +hurd (20050507-1) unstable; urgency=low + + * New snapshot from CVS. + + Contains libpthread fixes for various test suites by Neal + Walfield. + * debian/changelog (20050119-3): Added overlooked Closes: tag. + * debian/control (hurd-dbg/Priority:) Set to extra as requested by + the ftp-masters. + * debian/patches/isofs_boot.patch: Removed, applied upstream. + * debian/patches/libpthread_linker_script.patch: Likewise. + + -- Michael Banck <mbanck@debian.org> Sat, 7 May 2005 15:28:51 +0200 + +hurd (20050119-3) unstable; urgency=low + + * debian/control (hurd-dbg): New package. + * debian/rules (DEB_DH_STRIP_ARGS): Add support for hurd-dbg. + * debian/hurd-dbg.dirs: New file. + * debian/control (hurd-doc): New package. (Closes: #264858) + (Build-Depends-Indep): Added texi2html. + * debian/rules (build/hurd::): Generate html version of the manual. + * debian/hurd-doc.info: New file. + * debian/hurd-doc.docs: New file. + + -- Michael Banck <mbanck@debian.org> Fri, 15 Apr 2005 23:03:34 +0200 + +hurd (20050119-2) unstable; urgency=low + + [ Michael Banck ] + * debian/hurd-dev.install: Install development libraries into /lib, + not /usr/lib. + * debian/hurd.install: Install Hurd console drivers into + /usr/lib/hurd/console, not /lib/hurd/console. + * debian/copyright: Clarify that the FSF is the copyright holder. + * debian/copyright: Update download location to Savannah's GNU Hurd + project page. + + -- Michael Banck <mbanck@debian.org> Mon, 4 Apr 2005 12:08:40 +0200 + +hurd (20050119-1) unstable; urgency=low + + * New snapshot from CVS. + + Contains libpthread header fixes by Neal Walfield and + Pietro Ferrari. (Closes: #184344) + + Contains console repeaters by Marco Gerards. + + Contains mount argp fixes. (Closes: #151407) + + [ Michael Banck] + * debian/patches/exec.patch: Removed, no longer needed. + * debian/patches/mouse.patch: Likewise. + * debian/patches/console_repeater.patch: Removed, applied upstream. + * debian/patches/libcons_repeater.patch: Likewise. + * debian/patches/netfs_io_select.patch: Likewise. + * debian/patches/netfs_nonblock.patch: Likewise. + * debian/patches-contrib/kbd.patch: Removed, no longer needed. + * debian/patches/libpthread_linker_script.patch: New patch. Install + libpthread.a linker script correctly. (Closes: #291307) + * debian/rules (install/hurd::): Rename /bin/fakeroot to + /bin/fakeroot-hurd. + * debian/control (hurd): Removed fakeroot from Provides:, Replaces: + and Conflicts:. (Closes: #293511) + * debian/hurd.install: Install debian/tmp/bin/fakeroot-hurd instead + of debian/tmp/bin/fakeroot. + * NEWS: New file. Explain the console-client command line interface + changes. + * debian/patches/siocgifhwaddr.patch: New patch by Marco Gerards. + * debian/patches/isofs_boot.patch: New patch by Alfred M. Szmidt. + + -- Michael Banck <mbanck@debian.org> Wed, 23 Feb 2005 20:52:07 +0100 + +hurd (20040508-6) unstable; urgency=low + + [ Michael Banck ] + * debian/patches/pfinet_dhcp.patch: New patch by Marco Gerards. + + -- Michael Banck <mbanck@debian.org> Sat, 15 Jan 2005 21:04:33 +0100 + +hurd (20040508-5) unstable; urgency=low + + [ Michael Banck ] + * debian/patches-contrib/ext2fs_20040930.diff: Moved to ... + * debian/patches/ext2fs_large_stores.diff: ... here, updated from + Ognyan Kulev's 20041111 version. Set DISK_CACHE_BLOCKS to + 65536 in ext2fs.h. + + -- Michael Banck <mbanck@debian.org> Sun, 12 Dec 2004 17:54:32 +0100 + +hurd (20040508-4) unstable; urgency=low + + [ Michael Banck ] + * debian/changelog: Added back 20040301-1 entry which got lost. + * debian/hurd.install: Do not install /sbin/fsck. (Closes: #272655) + * debian/patches/rc.patch: Updated to use e2fsprog's /sbin/fsck + command-line options. Make sure the root file system is read-only + during the fsck run, and update it to be writable again if fsck + succeeds. (Closes: #273508) + * debian/patches-contrib/ext2fs_20040930.diff: New file. Just put it + in debian/patches and recompile the package to get (experimental) + support for ext2 files systems larger than 2GB. + * debian/control (Maintainer): Changed Maintainer address. + + [ Guillem Jover ] + * debian/hurd.postinst: + - Move /bin/login suid root chmod to debian/rules. + - Set suid bit to other binaries (/bin/ps, /bin/ids, /bin/w). + (Closes: #273507) + Thanks Ognyan Kulev <ogi@fmi.uni-sofia.bg>. + + -- Michael Banck <mbanck@debian.org> Thu, 7 Oct 2004 20:11:38 +0200 + +hurd (20040508-3) unstable; urgency=low + + * debian/local/rc: Removed. + * debian/patches/rc.patch: New file. (Closes: #254147) + * debian/hurd.install: Install tmp/libexec/rc. + * debian/patches/console_switch3.patch: Removed. + * debian/patches/console_repeater.patch: New patch by Marco Gerards. + * debian/patches/libcons_repeater.patch: New patch by Marco Gerards. + * debian/patches/netfs_io_select.patch: New patch by Marco Gerards. + * debian/patches/netfs_nonblock.patch: New patch by Marco Gerards. + * Rebuilt against glibc_2.3.2.ds1-16. + * debian/hurd.postinst: Make sure /bin/login is suid. (Closes: #251863) + * debian/control (Uploaders): Added myself. + * debian/hurd.postinst: Only create the tty devices if they do not + exist already. (Closes: #268347) + + -- Michael Banck <mbanck@debian.org> Thu, 9 Sep 2004 22:32:07 +0200 + +hurd (20040508-2) unstable; urgency=low + + * Fix typo in postinst. (Closes: #253662) + Thanks to Michael Banck. + * Support /usr tree in startup scripts (Closes: #229572) + Thanks to Guillem Jover + + -- Jeff Bailey <jbailey@raspberryginger.com> Fri, 11 Jun 2004 11:17:26 -0400 + +hurd (20040508-1) unstable; urgency=low + + * New snapshot from CVS. + * Switch packaging to cdbs + * Do not provide /boot/serverboot or /boot/servers.boot + * Update policy to 3.6.1.0 + * Do not provide update-rc.d, use the one from sysvinit instead + (Closes: #246813) - Thanks to Robert Millan + * Do not provide /sbin/fsck, use the one from e2fsprogs instead + Thanks to Robert Millan + + -- Jeff Bailey <jbailey@raspberryginger.com> Sat, 8 May 2004 16:55:18 -0400 + +hurd (20040301-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. exec/exec.c PT_GNU_STACK work-around. + Provide example entries for new console in config/ttys. + * debian/rules: Do not call autoconf. + * debian/control: Remove build dependency autoconf. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 1 Mar 2004 01:36:23 +0200 + +hurd (20021118-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual, with bug fixes from David Walter. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 18 Nov 2002 21:32:22 +0200 + +hurd (20021011-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. + Build libpthread. + debian/control: Add libncursesw5-dev as build-dependency. + debian/shlibs: Add libpthread + debian/control: Add myself as an uploader. + + -- Neal H. Walfield <neal@debian.org> Fri, 11 Oct 2002 21:42:21 -0400 + +hurd (20020918-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 18 Sep 2002 23:13:06 +0200 + +hurd (20020804-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 4 Aug 2002 20:46:28 +0200 + +hurd (20020523-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 23 May 2002 15:29:40 +0200 + +hurd (20020418-1) unstable; urgency=low + + * New snapshot from CVS. + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 18 Apr 2002 15:22:39 +0200 + +hurd (20011105-1) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual (well, the intention was there :). + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 5 Nov 2001 00:00:26 +0100 + +hurd (20011016-1) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 16 Oct 2001 19:43:21 +0200 + +hurd (20011013-1) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + * debian/rules: Change way how to find executables by Kevin Kreamer. + * debian/control: Add `file' to build dependencies by Kevin Kreamer. + + -- Marcus Brinkmann <brinkmd@debian.org> Sat, 13 Oct 2001 01:05:30 +0200 + +hurd (20010817-2) unstable; urgency=low + + * Include a copy of update-rc.d, moved from dpkg to init providing + package. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 2 Sep 2001 19:40:00 +0200 + +hurd (20010817-1) unstable; urgency=low + + * New snapshot from CVS, closes: #105476, #39894. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 17 Aug 2001 22:16:01 +0200 + +hurd (20010718-1) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 18 Jul 2001 21:43:52 +0200 + +hurd (20010608) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + Compiled with -O2 rather than -O3. + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 8 Jun 2001 23:02:47 +0200 + +hurd (20010527) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Sat, 27 May 2001 01:34:21 +0200 + +hurd (20010426) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + storeio hack to prevent double activation. + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 27 Apr 2001 00:09:56 +0200 + +hurd (20010311) unstable; urgency=low + + * New snapshot from CVS. + * Additional patches: + kbd, mouse as usual. + Change terminal type to mach-color. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 11 Mar 2001 22:45:21 +0100 + +hurd (20010111) unstable; urgency=low + + * New snapshot from CVS, containing lots of small bug fixes, and: + + Together with gnumach 1.2-9, you can access large stores with + storeinfo, storeread (because libstore uses the new interface in + gnumach, and off64_t internally). + + pfinet contains support for network ioctls. The corresponding + changes in the glibc library are not available in Debian yet, though. + * streamdev is renamed to streamio. + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 12 Jan 2001 00:06:41 +0100 + +hurd (20001204) unstable; urgency=low + + * New snapshot from CVS, with a couple of bug fixes: + pfinet: Don't leak references. + ext2fs, ufs: Avoid a dn_set_?time vs sync thread race. + Corretly deny too long filenames. + nfsd: Fix a couple of memory leaks. + + * Additional patchs: + libdiskfs: Don't crash when symlink target is the empty string. + streamdev, kbd, mouse: New translators for X and klog device. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 4 Dec 2000 15:18:39 +0100 + +hurd (20001127) unstable; urgency=low + + * New snapshot from CVS, really fixes isofs now. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 27 Nov 2000 21:07:03 +0100 + +hurd (20001126) unstable; urgency=low + + * New snapshot from CVS, closes: #68417, #69281, #68626 + * Fix in 20001030 closes: #72319 + * debian/control: Add build dependencies, closes: #75734 + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 26 Nov 2000 05:53:19 +0100 + +hurd (20001030) unstable; urgency=low + + * New snapshot from CVS. + * Still contains all the goodies, streadev, kbd, mouse. Now opening + kbd, mouse more than once doesn't crash them (thanks Erik Verbruggen + <ejv@cs.kun.nl>) + * sutils/MAKEDEV.sh: kmsg is really klog. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 30 Oct 2000 18:02:29 +0200 + +hurd (20000921) unstable; urgency=low + + * New snapshot from CVS + * Add streamdev by OKUJI Yoshinori + (source: ftp://alpha.gnu.org/contrib/okuji/hurd/streamdev-19990920.tar.gz) + * Add kbd and mouse by UCHIYAMA Yasushi <uch@nop.or.jp>. + * sutils/MAKEDEV.sh: Add kbd and kmsg. No sense to add mouse, as you need + to configure it (see /hurd/mouse --help). + + -- Marcus Brinkmann <brinkmd@debian.org> Sat, 23 Sep 2000 04:27:58 +0200 + +hurd (20000803) unstable; urgency=low + + * New snapshot from CVS. + * isofs: Patch to fix symlink handling. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 3 Aug 2000 21:09:44 +0200 + +hurd (20000726) unstable; urgency=low + + * New snapshot from CVS. + * Fixes the infamous zero hole bug (actually both of them). + + -- Marcus Brinkmann <brinkmd@debian.org> Wed, 26 Jul 2000 02:24:06 +0200 + +hurd (20000703) unstable; urgency=low + + * New snapshot from CVS. + * exec/hashexec.c (check_hashbang: Fix off by one error in line 178. + Patch by Kalle Olavi Niemital. + + -- Marcus Brinkmann <bug-hurd@gnu.org> Mon, 3 Jul 2000 00:44:47 +0200 + +hurd (20000130) unstable; urgency=low + + * New snapshot from CVS. Closes: Bug#54282, Bug#40302, Bug#56076. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 30 Jan 2000 14:55:39 +0100 + +hurd (19991209) unstable; urgency=low + + * New snapshot from CVS. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 9 Dec 1999 23:43:23 +0100 + +hurd (19991022) unstable; urgency=low + + * New snapshot from CVS. + * libdiskfs/init-startup.c: Disable periodic syncing before shutting down. + This fixes the fs-unclean-on-reboot bug! + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 22 Oct 1999 21:32:02 +0200 + +hurd (19991004) unstable; urgency=high + + * New snapshot from CVS. + term: Realize bogus devices. + ext2fs: Important bug fixes! + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 3 Oct 1999 18:01:17 +0200 + +hurd (19990923) unstable; urgency=low + + * New snapshot from CVS. + MAKEDEV: pty created with mode 0666. + Implements pathconf for libdiskfs and libnetfs. + Various bug fixes. + * Development package now includes pic libraries. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 19 Sep 1999 19:29:00 +0200 + +hurd (19990907) unstable; urgency=low + + * New snapshot from CVS. + * gzip /boot/serverboot to /boot/serverboot.gz + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 23 Aug 1999 15:12:10 +0200 + +hurd (19990725) unstable; urgency=low + + * New snapshot from CVS. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 25 Jul 1999 16:16:03 +0200 + +hurd (19990714) unstable; urgency=low + + * New snapshot from CVS. + * debian/rules: etc/motd is in base-files, do not include it. + * Activate split-init. + + -- Marcus Brinkmann <brinkmd@debian.org> Wed, 14 Jul 1999 16:38:00 +0200 + +hurd (19990616) unstable; urgency=low + + * New snapshot from CVS. + * Now contains info and ps documentation. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 17 Jun 1999 17:35:54 +0200 + +hurd (19990524) unstable; urgency=low + + * New snapshot from CVS. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 24 May 1999 15:09:45 +0200 + +hurd (19990523) unstable; urgency=low + + * New snapshot from CVS, fixes: #38062, #37670, #37878, #37944. + + -- Marcus Brinkmann <brinkmd@debian.org> Mon, 24 May 1999 01:08:26 +0200 + +hurd (19990517fixed) unstable; urgency=low + + * debian/shlibs: corrected. + * exec/hashexec.c: Applied patch by Roland to make it work. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 17 May 1999 00:25:11 +0200 + +hurd (19990517) unstable; urgency=low + + * New snapshot from CVS. + * Add shlibs file. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 16 May 1999 15:28:09 +0200 + +hurd (19990425-1) unstable; urgency=low + + * Put shared library symlinks into the hurd-dev package. + * Clarify instructions in provided servers.boot. + * libfshelp/fetch-root.c: De-patched a change by tb which produced + strange errors. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 29 Apr 1999 22:47:51 +0200 + +hurd (19990212-2) unstable; urgency=low + + * debian/control: Added Depends line for Hurd. + * Update docs to reflect new group maintainership. + * debian/copyright: Hurd libraries are *not* under the LGPL, so add a + clarifying note. + * Put static libraries and header files into /usr/lib and /usr/include + for people without the /usr symlink. + + -- Gordon Matzigkeit <bug-hurd@gnu.org> Wed, 17 Feb 1999 15:40:44 -0600 + +hurd (19990212-1) unstable; urgency=low + + * New upstream version from CVS. + * Deleted old libthreads... there's no going back now. + + -- Gordon Matzigkeit <gord@debian.org> Fri, 12 Feb 1999 03:25:55 -0600 + +hurd (19981204-1) unstable; urgency=low + + * New upstream release, supposed to work with glibc 2.0.106. + * Commented out use of old libthreads. + + -- Marcus Brinkmann <brinkmd@debian.org> Sun, 20 Dec 1998 04:24:40 +0100 + +hurd (19980915-2) unstable; urgency=low + + * exec/hashexec.c: Applied patch by Thomas Bushnell to fix make. + + -- Marcus Brinkmann <brinkmd@debian.org> Fri, 6 Nov 1998 23:10:11 +0100 + +hurd (19980915-1) unstable; urgency=low + + * New upstream release. + * debian/rules: Strip all binaries. + * debian/TODO: New file. + + -- Marcus Brinkmann <brinkmd@debian.org> Thu, 8 Oct 1998 03:34:40 +0200 + +hurd (19980716-2) unstable; urgency=low + + * Reverted libthreads to provide threadsafe malloc, as we use older + version of glibc2 for now. + * Do not remove size 0 files in 'rules clean', because hurd depends on + them. + * Do not build profiling libraries. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 4 Aug 1998 21:58:55 +0200 + +hurd (19980716-1) unstable; urgency=low + + * Initial Version. + + -- Marcus Brinkmann <brinkmd@debian.org> Tue, 4 Aug 1998 21:58:55 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..8b11f485 --- /dev/null +++ b/debian/control @@ -0,0 +1,65 @@ +Source: hurd +Section: admin +Priority: required +Maintainer: GNU Hurd Maintainers <debian-hurd@lists.debian.org> +Standards-Version: 3.8.4 +Build-Depends: mig (>= 1.3-2), gnumach-dev (>= 2:1.3.99.dfsg.cvs20070526), + libc0.3-dev (>= 2.9), texinfo, texi2html, libncursesw5-dev, cdbs, + debhelper (>= 4.2.0), gcc-4.3, dpkg (>= 1.15.4) | install-info +Uploaders: Jeff Bailey <jbailey@raspberryginger.com>, + Neal H. Walfield <neal@debian.org>, Michael Banck <mbanck@debian.org>, + Samuel Thibault <sthibault@debian.org> +Homepage: http://www.gnu.org/software/hurd/hurd.html +Vcs-Browser: http://svn.debian.org/wsvn/pkg-hurd/hurd/ +Vcs-Svn: svn://svn.debian.org/pkg-hurd/hurd/trunk/ + +Package: hurd +Essential: yes +Depends: ${misc:Depends}, gnumach (>= 2:1.3.99.dfsg.cvs20070526-1), sysv-rc, ${shlibs:Depends} +Suggests: hurd-doc +Provides: makedev, login +Replaces: makedev, login +Conflicts: makedev, login +Architecture: hurd-i386 +Description: The GNU Hurd + This is the GNU Hurd package. It contains essential system software and + libraries. + +Package: hurd-dev +Priority: standard +Section: libdevel +Architecture: hurd-i386 +Depends: ${misc:Depends}, hurd +Provides: libsem-dev +Replaces: libsem-dev +Conflicts: libsem-dev +Description: The GNU Hurd (development files) + This package includes the header files and the static libraries. + +Package: hurd-dbg +Priority: extra +Section: debug +Architecture: hurd-i386 +Depends: ${misc:Depends}, hurd (= ${binary:Version}) +Description: The GNU Hurd (debugging files) + This package includes the unstripped binaries and libraries. + +Package: hurd-doc +Priority: optional +Section: doc +Architecture: all +Depends: ${misc:Depends} +Suggests: hurd (>= ${source:Version}) +Description: The GNU Hurd manual + This package includes the manual in info and HTML format. + +Package: hurd-udeb +XC-Package-Type: udeb +Priority: optional +Section: debian-installer +Architecture: hurd-i386 +Depends: ${misc:Depends} +Provides: hurd, ext2-modules, fat-modules, ipv6-modules, isofs-modules, loop-modules, mouse-modules, nfs-modules, socket-modules, ufs-modules +Description: The GNU Hurd - udeb + This is the GNU Hurd udeb package. It contains essential system software and + libraries. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..e222a536 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,31 @@ +This package was debianized by Marcus Brinkmann <brinkmd@debian.org> +on Tue, 4 Aug 1998 21:52:45 +0200 + +It is currently maintained by the Debian GNU Hurd maintainers, who can be +reached via <debian-hurd@lists.debian.org>. + +Sources are available from http://savannah.gnu.org/projects/hurd + +Copyright statement: + +The GNU Hurd is copyrighted by the Free Software Foundation, Inc. + +Note that the libraries distributed with the GNU Hurd are placed under +the standard GNU General Public License (*not* the Library General +Public License). + + 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; version 2 dated June, 1991. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU General Public License +version 2 can be found in `/usr/share/common-licenses/GPL-2'. diff --git a/debian/hurd-console.default b/debian/hurd-console.default new file mode 100644 index 00000000..1126516c --- /dev/null +++ b/debian/hurd-console.default @@ -0,0 +1,36 @@ +# Options to start the Hurd console. + +# Set this to 'true' to run the Hurd console on bootup. +ENABLE='false' + +# The display driver, mandatory. Either `vga' or `ncursesw'. +DISPLAY='-d vga' + +# The keyboard driver, mandatory. Either `pc_kbd' or `xkb' from the +# console-driver-xkb package. +KBD='-d pc_kbd' + +# The alternative xkb keyboard driver, as provided by the +# console-driver-xkb package. It uses X11 style keymaps and supports +# different keymaps. Possible options are: +# --keymap: The keymap to use. By default en_US is used. Examples of +# some other keymaps are: fr, us, de, dvorak. +# --keymapfile: The file that hold the descriptions of the default +# keymaps file. This file holds the description of all keymaps. This +# path should be relative to the path set by `xkbdir'. By default +# "keymap/xfree86" is used. +# --xkbdir: The root directory of the xkb configuration, by default +# this is /etc/X11/xkb. +#KBD='-d xkb' + +# The keyboard repeater. Required for running X11. +#KBD_REPEAT='--repeat=kbd' + +# The mouse driver. Optional. +#MOUSE='-d pc_mouse --protocol=ps/2' + +# The mouse repeater. Required for running X11. +#MOUSE_REPEAT='--repeat=mouse' + +# The pc speaker. Optional. +#SPEAKER='-d generic_speaker' diff --git a/debian/hurd-dbg.dirs b/debian/hurd-dbg.dirs new file mode 100644 index 00000000..08d9e7ae --- /dev/null +++ b/debian/hurd-dbg.dirs @@ -0,0 +1 @@ +usr/lib/debug diff --git a/debian/hurd-dev.install b/debian/hurd-dev.install new file mode 100644 index 00000000..7bd68e9f --- /dev/null +++ b/debian/hurd-dev.install @@ -0,0 +1,3 @@ +debian/tmp/lib/*.a lib +debian/tmp/include/* usr/include +debian/tmp/lib/*.so lib diff --git a/debian/hurd-doc.docs b/debian/hurd-doc.docs new file mode 100644 index 00000000..5d7f66d2 --- /dev/null +++ b/debian/hurd-doc.docs @@ -0,0 +1,2 @@ +build/doc/hurd*html +doc/navigating diff --git a/debian/hurd-doc.info b/debian/hurd-doc.info new file mode 100644 index 00000000..183900da --- /dev/null +++ b/debian/hurd-doc.info @@ -0,0 +1 @@ +debian/tmp/share/info/hurd.info diff --git a/debian/hurd-udeb.install b/debian/hurd-udeb.install new file mode 100644 index 00000000..361d3504 --- /dev/null +++ b/debian/hurd-udeb.install @@ -0,0 +1,63 @@ +debian/local/runsystem libexec +debian/tmp/lib/*.so.* +debian/tmp/lib/hurd/console/*.so.* usr/lib/hurd/console +debian/tmp/libexec/console-run +debian/tmp/sbin/e2os +debian/tmp/sbin/MAKEDEV +debian/tmp/sbin/losetup +debian/tmp/sbin/swapon +debian/tmp/sbin/swapoff +debian/tmp/bin/boot +debian/tmp/bin/console +debian/tmp/bin/shd +debian/tmp/bin/ps-hurd +debian/tmp/bin/settrans +debian/tmp/bin/showtrans +debian/tmp/bin/syncfs +debian/tmp/bin/fsysopts +debian/tmp/bin/storeinfo +debian/tmp/bin/login +debian/tmp/usr/bin/w-hurd +debian/tmp/usr/bin/uptime-hurd +debian/tmp/bin/ids +debian/tmp/bin/loginpr +debian/tmp/bin/sush +debian/tmp/usr/bin/vmstat-hurd +debian/tmp/bin/portinfo +debian/tmp/bin/devprobe +debian/tmp/bin/vminfo +debian/tmp/bin/addauth +debian/tmp/bin/rmauth +debian/tmp/bin/unsu +debian/tmp/bin/setauth +debian/tmp/bin/storecat +debian/tmp/bin/storeread +debian/tmp/bin/msgport +debian/tmp/bin/mount +debian/tmp/dev/MAKEDEV +debian/tmp/hurd/auth +debian/tmp/hurd/console +debian/tmp/hurd/exec +debian/tmp/hurd/ext2fs +debian/tmp/hurd/ext2fs.static /boot +debian/tmp/hurd/fatfs +debian/tmp/hurd/fifo +debian/tmp/hurd/firmlink +debian/tmp/hurd/fwd +debian/tmp/hurd/ifsock +debian/tmp/hurd/init +debian/tmp/hurd/iso9660fs +debian/tmp/hurd/mach-defpager +debian/tmp/hurd/magic +debian/tmp/hurd/new-fifo +debian/tmp/hurd/null +debian/tmp/hurd/pfinet +debian/tmp/hurd/pflocal +debian/tmp/hurd/proc +debian/tmp/hurd/procfs +debian/tmp/hurd/proxy-defpager +debian/tmp/hurd/storeio +debian/tmp/hurd/streamio +debian/tmp/hurd/symlink +debian/tmp/hurd/term +debian/tmp/hurd/tmpfs diff --git a/debian/hurd.dirs b/debian/hurd.dirs new file mode 100644 index 00000000..7af900ee --- /dev/null +++ b/debian/hurd.dirs @@ -0,0 +1,7 @@ +servers +servers/socket +etc/default +etc/sysctl.d +usr/share/msgids +usr/bin +boot diff --git a/debian/hurd.examples b/debian/hurd.examples new file mode 100644 index 00000000..8b0bfeea --- /dev/null +++ b/debian/hurd.examples @@ -0,0 +1 @@ +debian/local/menu.lst diff --git a/debian/hurd.install b/debian/hurd.install new file mode 100644 index 00000000..bd27df90 --- /dev/null +++ b/debian/hurd.install @@ -0,0 +1,65 @@ +debian/tmp/lib/*.so.* +debian/tmp/lib/hurd/console/*.so.* usr/lib/hurd/console +debian/tmp/hurd/* +debian/tmp/libexec/rc +debian/tmp/libexec/getty +debian/tmp/libexec/console-run +debian/tmp/libexec/runttys +debian/tmp/libexec/runsystem.gnu +debian/tmp/sbin/nfsd +debian/tmp/sbin/e2os +debian/tmp/sbin/MAKEDEV +debian/tmp/sbin/losetup +debian/tmp/sbin/reboot +debian/tmp/sbin/halt +debian/tmp/sbin/swapon +debian/tmp/sbin/swapoff +debian/tmp/sbin/fsck.ufs +debian/tmp/sbin/mkfs.ufs +debian/tmp/sbin/clri.ufs +debian/tmp/sbin/stati.ufs +debian/tmp/bin/boot +debian/tmp/bin/console +debian/tmp/bin/shd +debian/tmp/bin/ps-hurd +debian/tmp/bin/settrans +debian/tmp/bin/showtrans +debian/tmp/bin/syncfs +debian/tmp/bin/fsysopts +debian/tmp/bin/storeinfo +debian/tmp/bin/login +debian/tmp/usr/bin/w-hurd +debian/tmp/usr/bin/uptime-hurd +debian/tmp/bin/ids +debian/tmp/bin/loginpr +debian/tmp/bin/sush +debian/tmp/usr/bin/vmstat-hurd +debian/tmp/bin/portinfo +debian/tmp/bin/devprobe +debian/tmp/bin/vminfo +debian/tmp/bin/addauth +debian/tmp/bin/rmauth +debian/tmp/bin/unsu +debian/tmp/bin/setauth +debian/tmp/bin/ftpcp +debian/tmp/bin/ftpdir +debian/tmp/bin/storecat +debian/tmp/bin/storeread +debian/tmp/bin/msgport +debian/tmp/bin/rpctrace +debian/tmp/bin/mount +debian/tmp/bin/gcore +debian/tmp/bin/fakeauth +debian/tmp/usr/bin/fakeroot-hurd +debian/tmp/bin/forks +debian/tmp/bin/timertest +debian/tmp/bin/fstests +debian/tmp/etc/login +debian/tmp/etc/login/.bash_login +debian/tmp/etc/login/.bashrc +debian/tmp/etc/login/.hushlogin +debian/tmp/etc/login/.profile +debian/tmp/etc/login/README +debian/tmp/etc/ttys +debian/tmp/dev/MAKEDEV +debian/tmp/share/msgids/hurd.msgids usr/share/msgids diff --git a/debian/hurd.postinst b/debian/hurd.postinst new file mode 100644 index 00000000..3713c7e6 --- /dev/null +++ b/debian/hurd.postinst @@ -0,0 +1,48 @@ +#!/bin/sh + +set -e + +update-alternatives --quiet \ + --install /libexec/runsystem runsystem /libexec/runsystem.gnu 20 + +update-alternatives \ + --install /usr/bin/fakeroot fakeroot /usr/bin/fakeroot-hurd 30 + +update-alternatives \ + --install /bin/ps ps /bin/ps-hurd 60 + +update-alternatives \ + --install /usr/bin/uptime uptime /usr/bin/uptime-hurd 30 + +update-alternatives \ + --install /usr/bin/vmstat vmstat /usr/bin/vmstat-hurd 60 + +update-alternatives \ + --install /usr/bin/w w /usr/bin/w-hurd 60 + +#DEBHELPER# + +for i in vcs tty1 tty2 tty3 tty4 tty5 tty6; do + if ! [ -e /dev/$i ]; then + cd /dev + /sbin/MAKEDEV $i || true + fi +done + +if [ ! -h /dev/mouse ]; then + ln -s /dev/cons/mouse /dev/mouse +fi + +if [ ! -h /dev/kbd ]; then + ln -s /dev/cons/kbd /dev/kbd +fi + +if [ ! -e /dev/shm ]; then + mkdir /dev/shm + chmod 1777 /dev/shm +fi + +if [ ! -e /proc ]; then + mkdir /proc + settrans -c /proc /hurd/procfs +fi diff --git a/debian/local/menu.lst b/debian/local/menu.lst new file mode 100644 index 00000000..9e2ba4c0 --- /dev/null +++ b/debian/local/menu.lst @@ -0,0 +1,19 @@ +# Example GRUB configuration to boot Debian GNU/Hurd off the first partition. +# Adjust the partition setting for GRUB's root command and the gnumach.gz +# root device. + +timeout 5 + +default 0 + +title Debian GNU/Hurd +root (hd0,0) +kernel /boot/gnumach.gz root=device:hd0s1 +module /hurd/ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume) +module /lib/ld.so.1 /hurd/exec $(exec-task=task-create) + +title Debian GNU/Hurd (single user mode) +root (hd0,0) +kernel /boot/gnumach.gz -s root=device:hd0s1 +module /hurd/ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume) +module /lib/ld.so.1 /hurd/exec $(exec-task=task-create) diff --git a/debian/local/runsystem b/debian/local/runsystem new file mode 100755 index 00000000..54354dc7 --- /dev/null +++ b/debian/local/runsystem @@ -0,0 +1,79 @@ +#!/bin/sh + +PATH=/bin:/sbin:/usr/bin:/usr/sbin +export PATH + +# Usage: foldsubst <pat> xxxx yyyy zzzz ... +# <pat> is substituted for every character of xxxx with sed, the character in +# question being accessible as a '\0' in <pat>, and the result is used as the +# new pattern to handle the remaining arguments. +foldsubst () { + [ "$2" ] || { echo $1; return; } + expanded=$(echo "$2" | sed "s/./ $1/g"); shift 2 + foldsubst "$expanded" $@; +} + +# Verbosely attach a translator. +st () { + echo -n " $1" + settrans -ck /servers/$1 /hurd/$2 +} + +# Verbosely create device nodes, +# after the aguments are filtered through foldsubst. +md () { + pattern=$1; shift + sedrepl=$(echo $pattern | sed -e 's/X/\\0/' -e 's/Y/\\\\0/') + devs=$(foldsubst "$sedrepl" $@) + (cd /dev; ./MAKEDEV $devs) + echo -n " $pattern" +} + + +echo -n "Setting up translators:" +mkdir -p /servers/socket +ln -s 1 /servers/socket/local +ln -s 2 /servers/socket/inet +st socket/1 pflocal +st socket/2 pfinet +st exec exec +st default-pager proxy-defpager +echo . + +echo -n "Creating device nodes:" +md 'fd std vcs' +md ttyX 1234 +md ptypX 0123 +md loopX 0123 +md hdX 0123 +md hdXsY 0123 12345678 +echo . + +echo -n "Starting procfs" +settrans -g /proc /hurd/procfs +echo . + +echo -n "Starting the Hurd console..." +# Touch the first tty so that the Hurd console is certain to pick it +# and not some random other tty. +sleep 1 +touch /dev/tty1 +console -d vga -d pc_kbd -c /dev/vcs & +sleep 1 +# Switch over +exec < /dev/tty1 > /dev/tty1 2>&1 +echo "Console started." + +# Set the console device used by /sbin/reopen-console +echo /dev/tty1 >/var/run/console-device + +TERM=hurd +export TERM + +# Preset the terminal type for /lib/debian-installer/detect-console +TERM_TYPE=virtual +export TERM_TYPE + +# Invoke init as linuxrc to work around pid != 1 +exec /bin/busybox linuxrc + diff --git a/debian/local/soundcard.h b/debian/local/soundcard.h new file mode 100644 index 00000000..3c32819a --- /dev/null +++ b/debian/local/soundcard.h @@ -0,0 +1,1298 @@ +#ifndef _SYS_SOUNDCARD_H +#define _SYS_SOUNDCARD_H +/* + * Copyright by Hannu Savolainen 1993-1997 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +/* + * OSS interface version. With versions earlier than 3.6 this value is + * an integer with value less than 361. In versions 3.6 and later + * it's a six digit hexadecimal value. For example value + * of 0x030600 represents OSS version 3.6.0. + * Use ioctl(fd, OSS_GETVERSION, &int) to get the version number of + * the currently active driver. + */ +#define SOUND_VERSION 0x030802 +#define OPEN_SOUND_SYSTEM + +#include <sys/ioctl.h> +#include <endian.h> + +/* + * Supported card ID numbers (Should be somewhere else?) + */ + +#define SNDCARD_ADLIB 1 +#define SNDCARD_SB 2 +#define SNDCARD_PAS 3 +#define SNDCARD_GUS 4 +#define SNDCARD_MPU401 5 +#define SNDCARD_SB16 6 +#define SNDCARD_SB16MIDI 7 +#define SNDCARD_UART6850 8 +#define SNDCARD_GUS16 9 +#define SNDCARD_MSS 10 +#define SNDCARD_PSS 11 +#define SNDCARD_SSCAPE 12 +#define SNDCARD_PSS_MPU 13 +#define SNDCARD_PSS_MSS 14 +#define SNDCARD_SSCAPE_MSS 15 +#define SNDCARD_TRXPRO 16 +#define SNDCARD_TRXPRO_SB 17 +#define SNDCARD_TRXPRO_MPU 18 +#define SNDCARD_MAD16 19 +#define SNDCARD_MAD16_MPU 20 +#define SNDCARD_CS4232 21 +#define SNDCARD_CS4232_MPU 22 +#define SNDCARD_MAUI 23 +#define SNDCARD_PSEUDO_MSS 24 +#define SNDCARD_GUSPNP 25 +#define SNDCARD_UART401 26 +/* Sound card numbers 27 to N are reserved. Don't add more numbers here. */ + +/*********************************** + * IOCTL Commands for /dev/sequencer + */ + +#ifndef _SIOWR +/* Use already defined ioctl defines if they exist (except with Sun or Sparc) */ +#define SIOCPARM_MASK IOCPARM_MASK +#define SIOC_VOID IOC_VOID +#define SIOC_OUT IOC_OUT +#define SIOC_IN IOC_IN +#define SIOC_INOUT IOC_INOUT +#define _SIOC_SIZE _IOC_SIZE +#define _SIOC_DIR _IOC_DIR +#define _SIOC_NONE _IOC_NONE +#define _SIOC_READ _IOC_READ +#define _SIOC_WRITE _IOC_WRITE +#define _SIO _IO +#define _SIOR _IOR +#define _SIOW _IOW +#define _SIOWR _IOWR +#endif /* !_SIOWR */ + +#define SNDCTL_SEQ_RESET _SIO ('q', 0) +#define SNDCTL_SEQ_SYNC _SIO ('q', 1) +#define SNDCTL_SYNTH_INFO _SIOWR('q', 2, struct synth_info) +#define SNDCTL_SEQ_CTRLRATE _SIOWR('q', 3, int) /* Set/get timer resolution (HZ) */ +#define SNDCTL_SEQ_GETOUTCOUNT _SIOR ('q', 4, int) +#define SNDCTL_SEQ_GETINCOUNT _SIOR ('q', 5, int) +#define SNDCTL_SEQ_PERCMODE _SIOW ('q', 6, int) +#define SNDCTL_FM_LOAD_INSTR _SIOW ('q', 7, struct sbi_instrument) /* Obsolete. Don't use!!!!!! */ +#define SNDCTL_SEQ_TESTMIDI _SIOW ('q', 8, int) +#define SNDCTL_SEQ_RESETSAMPLES _SIOW ('q', 9, int) +#define SNDCTL_SEQ_NRSYNTHS _SIOR ('q',10, int) +#define SNDCTL_SEQ_NRMIDIS _SIOR ('q',11, int) +#define SNDCTL_MIDI_INFO _SIOWR('q',12, struct midi_info) +#define SNDCTL_SEQ_THRESHOLD _SIOW ('q',13, int) +#define SNDCTL_SYNTH_MEMAVL _SIOWR('q',14, int) /* in=dev#, out=memsize */ +#define SNDCTL_FM_4OP_ENABLE _SIOW ('q',15, int) /* in=dev# */ +#define SNDCTL_SEQ_PANIC _SIO ('q',17) +#define SNDCTL_SEQ_OUTOFBAND _SIOW ('q',18, struct seq_event_rec) +#define SNDCTL_SEQ_GETTIME _SIOR ('q',19, int) +#define SNDCTL_SYNTH_ID _SIOWR('q',20, struct synth_info) +#define SNDCTL_SYNTH_CONTROL _SIOWR('q',21, struct synth_control) +#define SNDCTL_SYNTH_REMOVESAMPLE _SIOWR('q',22, struct remove_sample) + +typedef struct synth_control +{ + /* XXX */ + char data[62]; /* Device spesific command/data record */ + int devno; /* Synthesizer # */ +}synth_control; +#define _IOT_synth_control _IOT (_IOTS (char), 31, _IOTS (char), 31, _IOTS (int), 1) + +typedef struct remove_sample +{ + int devno; /* Synthesizer # */ + int bankno; /* MIDI bank # (0=General MIDI) */ + int instrno; /* MIDI instrument number */ +} remove_sample; +#define _IOT_remove_sample _IOT (_IOTS (int), 3, 0, 0, 0, 0) + +typedef struct seq_event_rec { + unsigned char arr[8]; +} seq_event_rec; +#define _IOT_seq_event_rec _IOT (_IOTS (char), 8, 0, 0, 0, 0) + +#define SNDCTL_TMR_TIMEBASE _SIOWR('t', 1, int) +#define SNDCTL_TMR_START _SIO ('t', 2) +#define SNDCTL_TMR_STOP _SIO ('t', 3) +#define SNDCTL_TMR_CONTINUE _SIO ('t', 4) +#define SNDCTL_TMR_TEMPO _SIOWR('t', 5, int) +#define SNDCTL_TMR_SOURCE _SIOWR('t', 6, int) +# define TMR_INTERNAL 0x00000001 +# define TMR_EXTERNAL 0x00000002 +# define TMR_MODE_MIDI 0x00000010 +# define TMR_MODE_FSK 0x00000020 +# define TMR_MODE_CLS 0x00000040 +# define TMR_MODE_SMPTE 0x00000080 +#define SNDCTL_TMR_METRONOME _SIOW ('t', 7, int) +#define SNDCTL_TMR_SELECT _SIOW ('t', 8, int) + +/* + * Some big endian/little endian handling macros + */ + +#if defined(__BYTE_ORDER) +# if __BYTE_ORDER == __BIG_ENDIAN +# define _PATCHKEY(id) (0xfd00|id) +# define AFMT_S16_NE AFMT_S16_BE +# elif __BYTE_ORDER == __LITTLE_ENDIAN +# define _PATCHKEY(id) ((id<<8)|0x00fd) +# define AFMT_S16_NE AFMT_S16_LE +# else +# error "could not determine byte order" +# endif +#endif + +/* + * Sample loading mechanism for internal synthesizers (/dev/sequencer) + * The following patch_info structure has been designed to support + * Gravis UltraSound. It tries to be universal format for uploading + * sample based patches but is probably too limited. + * + * (PBD) As Hannu guessed, the GUS structure is too limited for + * the WaveFront, but this is the right place for a constant definition. + */ + +struct patch_info { + unsigned short key; /* Use WAVE_PATCH here */ +#define WAVE_PATCH _PATCHKEY(0x04) +#define GUS_PATCH WAVE_PATCH +#define WAVEFRONT_PATCH _PATCHKEY(0x06) + + short device_no; /* Synthesizer number */ + short instr_no; /* Midi pgm# */ + + unsigned int mode; +/* + * The least significant byte has the same format than the GUS .PAT + * files + */ +#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */ +#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */ +#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */ +#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */ +#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */ +#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/ +#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */ +#define WAVE_FAST_RELEASE 0x80 /* bit 7 = Shut off immediately after note off */ + /* (use the env_rate/env_offs fields). */ +/* Linux specific bits */ +#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ +#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ +#define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +#define WAVE_FRACTIONS 0x00080000 /* Fraction information is valid */ +/* Reserved bits */ +#define WAVE_ROM 0x40000000 /* For future use */ +#define WAVE_MULAW 0x20000000 /* For future use */ +/* Other bits must be zeroed */ + + int len; /* Size of the wave data in bytes */ + int loop_start, loop_end; /* Byte offsets from the beginning */ + +/* + * The base_freq and base_note fields are used when computing the + * playback speed for a note. The base_note defines the tone frequency + * which is heard if the sample is played using the base_freq as the + * playback speed. + * + * The low_note and high_note fields define the minimum and maximum note + * frequencies for which this sample is valid. It is possible to define + * more than one samples for an instrument number at the same time. The + * low_note and high_note fields are used to select the most suitable one. + * + * The fields base_note, high_note and low_note should contain + * the note frequency multiplied by 1000. For example value for the + * middle A is 440*1000. + */ + + unsigned int base_freq; + unsigned int base_note; + unsigned int high_note; + unsigned int low_note; + int panning; /* -128=left, 127=right */ + int detuning; + +/* New fields introduced in version 1.99.5 */ + + /* Envelope. Enabled by mode bit WAVE_ENVELOPES */ + unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */ + unsigned char env_offset[ 6 ]; /* 255 == 100% */ + + /* + * The tremolo, vibrato and scale info are not supported yet. + * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or + * WAVE_SCALE + */ + + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + + int scale_frequency; + unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ + + int volume; + int fractions; + int reserved1; + int spare[2]; + char data[1]; /* The waveform data starts here */ + }; + +struct sysex_info { + short key; /* Use SYSEX_PATCH or MAUI_PATCH here */ +#define SYSEX_PATCH _PATCHKEY(0x05) +#define MAUI_PATCH _PATCHKEY(0x06) + short device_no; /* Synthesizer number */ + int len; /* Size of the sysex data in bytes */ + unsigned char data[1]; /* Sysex data starts here */ + }; + +/* + * /dev/sequencer input events. + * + * The data written to the /dev/sequencer is a stream of events. Events + * are records of 4 or 8 bytes. The first byte defines the size. + * Any number of events can be written with a write call. There + * is a set of macros for sending these events. Use these macros if you + * want to maximize portability of your program. + * + * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. + * (All input events are currently 4 bytes long. Be prepared to support + * 8 byte events also. If you receive any event having first byte >= 128, + * it's a 8 byte event. + * + * The events are documented at the end of this file. + * + * Normal events (4 bytes) + * There is also a 8 byte version of most of the 4 byte events. The + * 8 byte one is recommended. + */ +#define SEQ_NOTEOFF 0 +#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ +#define SEQ_NOTEON 1 +#define SEQ_FMNOTEON SEQ_NOTEON +#define SEQ_WAIT TMR_WAIT_ABS +#define SEQ_PGMCHANGE 3 +#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE +#define SEQ_SYNCTIMER TMR_START +#define SEQ_MIDIPUTC 5 +#define SEQ_DRUMON 6 /*** OBSOLETE ***/ +#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ +#define SEQ_ECHO TMR_ECHO /* For synching programs with output */ +#define SEQ_AFTERTOUCH 9 +#define SEQ_CONTROLLER 10 + +/******************************************* + * Midi controller numbers + ******************************************* + * Controllers 0 to 31 (0x00 to 0x1f) and + * 32 to 63 (0x20 to 0x3f) are continuous + * controllers. + * In the MIDI 1.0 these controllers are sent using + * two messages. Controller numbers 0 to 31 are used + * to send the MSB and the controller numbers 32 to 63 + * are for the LSB. Note that just 7 bits are used in MIDI bytes. + */ + +#define CTL_BANK_SELECT 0x00 +#define CTL_MODWHEEL 0x01 +#define CTL_BREATH 0x02 +/* undefined 0x03 */ +#define CTL_FOOT 0x04 +#define CTL_PORTAMENTO_TIME 0x05 +#define CTL_DATA_ENTRY 0x06 +#define CTL_MAIN_VOLUME 0x07 +#define CTL_BALANCE 0x08 +/* undefined 0x09 */ +#define CTL_PAN 0x0a +#define CTL_EXPRESSION 0x0b +/* undefined 0x0c */ +/* undefined 0x0d */ +/* undefined 0x0e */ +/* undefined 0x0f */ +#define CTL_GENERAL_PURPOSE1 0x10 +#define CTL_GENERAL_PURPOSE2 0x11 +#define CTL_GENERAL_PURPOSE3 0x12 +#define CTL_GENERAL_PURPOSE4 0x13 +/* undefined 0x14 - 0x1f */ + +/* undefined 0x20 */ +/* The controller numbers 0x21 to 0x3f are reserved for the */ +/* least significant bytes of the controllers 0x00 to 0x1f. */ +/* These controllers are not recognised by the driver. */ + +/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */ +/* 0=OFF and 127=ON (intermediate values are possible) */ +#define CTL_DAMPER_PEDAL 0x40 +#define CTL_SUSTAIN 0x40 /* Alias */ +#define CTL_HOLD 0x40 /* Alias */ +#define CTL_PORTAMENTO 0x41 +#define CTL_SOSTENUTO 0x42 +#define CTL_SOFT_PEDAL 0x43 +/* undefined 0x44 */ +#define CTL_HOLD2 0x45 +/* undefined 0x46 - 0x4f */ + +#define CTL_GENERAL_PURPOSE5 0x50 +#define CTL_GENERAL_PURPOSE6 0x51 +#define CTL_GENERAL_PURPOSE7 0x52 +#define CTL_GENERAL_PURPOSE8 0x53 +/* undefined 0x54 - 0x5a */ +#define CTL_EXT_EFF_DEPTH 0x5b +#define CTL_TREMOLO_DEPTH 0x5c +#define CTL_CHORUS_DEPTH 0x5d +#define CTL_DETUNE_DEPTH 0x5e +#define CTL_CELESTE_DEPTH 0x5e /* Alias for the above one */ +#define CTL_PHASER_DEPTH 0x5f +#define CTL_DATA_INCREMENT 0x60 +#define CTL_DATA_DECREMENT 0x61 +#define CTL_NONREG_PARM_NUM_LSB 0x62 +#define CTL_NONREG_PARM_NUM_MSB 0x63 +#define CTL_REGIST_PARM_NUM_LSB 0x64 +#define CTL_REGIST_PARM_NUM_MSB 0x65 +/* undefined 0x66 - 0x78 */ +/* reserved 0x79 - 0x7f */ + +/* Pseudo controllers (not midi compatible) */ +#define CTRL_PITCH_BENDER 255 +#define CTRL_PITCH_BENDER_RANGE 254 +#define CTRL_EXPRESSION 253 /* Obsolete */ +#define CTRL_MAIN_VOLUME 252 /* Obsolete */ +#define SEQ_BALANCE 11 +#define SEQ_VOLMODE 12 + +/* + * Volume mode decides how volumes are used + */ + +#define VOL_METHOD_ADAGIO 1 +#define VOL_METHOD_LINEAR 2 + +/* + * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as + * input events. + */ + +/* + * Event codes 0xf0 to 0xfc are reserved for future extensions. + */ + +#define SEQ_FULLSIZE 0xfd /* Long events */ +/* + * SEQ_FULLSIZE events are used for loading patches/samples to the + * synthesizer devices. These events are passed directly to the driver + * of the associated synthesizer device. There is no limit to the size + * of the extended events. These events are not queued but executed + * immediately when the write() is called (execution can take several + * seconds of time). + * + * When a SEQ_FULLSIZE message is written to the device, it must + * be written using exactly one write() call. Other events cannot + * be mixed to the same write. + * + * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the + * /dev/sequencer. Don't write other data together with the instrument structure + * Set the key field of the structure to FM_PATCH. The device field is used to + * route the patch to the corresponding device. + * + * For wave table use struct patch_info. Initialize the key field + * to WAVE_PATCH. + */ +#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ +#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */ + +/* + * Record for FM patches + */ + +typedef unsigned char sbi_instr_data[32]; + +struct sbi_instrument { + unsigned short key; /* FM_PATCH or OPL3_PATCH */ +#define FM_PATCH _PATCHKEY(0x01) +#define OPL3_PATCH _PATCHKEY(0x03) + short device; /* Synth# (0-4) */ + int channel; /* Program# to be initialized */ + sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */ + }; + +/* XXX */ +#define _IOT_sbi_instrument _IOT (_IOTS (short), 2, _IOTS (int), 1, _IOTS(char), 3) + +struct synth_info { /* Read only */ + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + int synth_type; +#define SYNTH_TYPE_FM 0 +#define SYNTH_TYPE_SAMPLE 1 +#define SYNTH_TYPE_MIDI 2 /* Midi interface */ + + int synth_subtype; +#define FM_TYPE_ADLIB 0x00 +#define FM_TYPE_OPL3 0x01 +#define MIDI_TYPE_MPU401 0x401 + +#define SAMPLE_TYPE_BASIC 0x10 +#define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC +#define SAMPLE_TYPE_WAVEFRONT 0x11 + + int perc_mode; /* No longer supported */ + int nr_voices; + int nr_drums; /* Obsolete field */ + int instr_bank_size; + unsigned int capabilities; +#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ +#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ +#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */ + int dummies[19]; /* Reserve space */ + }; +#define _IOT_synth_info _IOT (_IOTS (char), 30, _IOTS (int), 27, 0, 0) + +struct sound_timer_info { + char name[32]; + int caps; + }; + +#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */ + +struct midi_info { + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + unsigned int capabilities; /* To be defined later */ + int dev_type; + int dummies[18]; /* Reserve space */ + }; +#define _IOT_midi_info _IOT (_IOTS (char), 30, _IOTS (int), 21, 0, 0) + +/******************************************** + * ioctl commands for the /dev/midi## + */ +typedef struct { + unsigned char cmd; + char nr_args, nr_returns; + unsigned char data[30]; + } mpu_command_rec; +#define _IOT__IOTBASE_mpu_command_rec _IOT (_IOTS (char), 3, _IOTS (char), 30, 0, 0) + +#define SNDCTL_MIDI_PRETIME _SIOWR('m', 0, int) +#define SNDCTL_MIDI_MPUMODE _SIOWR('m', 1, int) +#define SNDCTL_MIDI_MPUCMD _SIOWR('m', 2, mpu_command_rec) + +/******************************************** + * IOCTL commands for /dev/dsp and /dev/audio + */ + +#define SNDCTL_DSP_RESET _SIO ('p', 0) +#define SNDCTL_DSP_SYNC _SIO ('p', 1) +#define SNDCTL_DSP_SPEED _SIOWR('p', 2, int) +#define SNDCTL_DSP_STEREO _SIOWR('p', 3, int) +#define SNDCTL_DSP_GETBLKSIZE _SIOWR('p', 4, int) +#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT +#define SNDCTL_DSP_CHANNELS _SIOWR('p', 6, int) +#define SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS +#define SOUND_PCM_WRITE_FILTER _SIOWR('p', 7, int) +#define SNDCTL_DSP_POST _SIO ('p', 8) +#define SNDCTL_DSP_SUBDIVIDE _SIOWR('p', 9, int) +#define SNDCTL_DSP_SETFRAGMENT _SIOWR('p',10, int) + +/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */ +#define SNDCTL_DSP_GETFMTS _SIOR ('p',11, int) /* Returns a mask */ +#define SNDCTL_DSP_SETFMT _SIOWR('p',5, int) /* Selects ONE fmt*/ +# define AFMT_QUERY 0x00000000 /* Return current fmt */ +# define AFMT_MU_LAW 0x00000001 +# define AFMT_A_LAW 0x00000002 +# define AFMT_IMA_ADPCM 0x00000004 +# define AFMT_U8 0x00000008 +# define AFMT_S16_LE 0x00000010 /* Little endian signed 16*/ +# define AFMT_S16_BE 0x00000020 /* Big endian signed 16 */ +# define AFMT_S8 0x00000040 +# define AFMT_U16_LE 0x00000080 /* Little endian U16 */ +# define AFMT_U16_BE 0x00000100 /* Big endian U16 */ +# define AFMT_MPEG 0x00000200 /* MPEG (2) audio */ +# define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */ + +/* + * Buffer status queries. + */ +typedef struct audio_buf_info { + int fragments; /* # of available fragments (partially usend ones not counted) */ + int fragstotal; /* Total # of fragments allocated */ + int fragsize; /* Size of a fragment in bytes */ + + int bytes; /* Available space in bytes (includes partially used fragments) */ + /* Note! 'bytes' could be more than fragments*fragsize */ + } audio_buf_info; +#define _IOT__IOTBASE_audio_buf_info _IOT (_IOTS (int), 4, 0, 0, 0, 0) + +#define SNDCTL_DSP_GETOSPACE _SIOR ('p',12, audio_buf_info) +#define SNDCTL_DSP_GETISPACE _SIOR ('p',13, audio_buf_info) +#define SNDCTL_DSP_NONBLOCK _SIO ('p',14) +#define SNDCTL_DSP_GETCAPS _SIOR ('p',15, int) +# define DSP_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */ +# define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */ +# define DSP_CAP_REALTIME 0x00000200 /* Real time capability */ +# define DSP_CAP_BATCH 0x00000400 /* Device has some kind of */ + /* internal buffers which may */ + /* cause some delays and */ + /* decrease precision of timing */ +# define DSP_CAP_COPROC 0x00000800 /* Has a coprocessor */ + /* Sometimes it's a DSP */ + /* but usually not */ +# define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */ +# define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */ +# define DSP_CAP_MULTI 0x00004000 /* support multiple open */ +# define DSP_CAP_BIND 0x00008000 /* channel binding to front/rear/cneter/lfe */ + + +#define SNDCTL_DSP_GETTRIGGER _SIOR ('p',16, int) +#define SNDCTL_DSP_SETTRIGGER _SIOW ('p',16, int) +# define PCM_ENABLE_INPUT 0x00000001 +# define PCM_ENABLE_OUTPUT 0x00000002 + +typedef struct count_info { + int bytes; /* Total # of bytes processed */ + int blocks; /* # of fragment transitions since last time */ + int ptr; /* Current DMA pointer value */ + } count_info; +#define _IOT__IOTBASE_count_info _IOT (_IOTS (int), 3, 0, 0, 0, 0) + +#define SNDCTL_DSP_GETIPTR _SIOR ('p',17, count_info) +#define SNDCTL_DSP_GETOPTR _SIOR ('p',18, count_info) + +typedef struct buffmem_desc { + unsigned *buffer; + int size; + } buffmem_desc; +/* XXX */ +/* #define SNDCTL_DSP_MAPINBUF _SIOR ('p', 19, buffmem_desc) */ +/* #define SNDCTL_DSP_MAPOUTBUF _SIOR ('p', 20, buffmem_desc) */ +#define SNDCTL_DSP_SETSYNCRO _SIO ('p', 21) +#define SNDCTL_DSP_SETDUPLEX _SIO ('p', 22) +#define SNDCTL_DSP_GETODELAY _SIOR ('p', 23, int) + +#define SNDCTL_DSP_GETCHANNELMASK _SIOWR('p', 64, int) +#define SNDCTL_DSP_BIND_CHANNEL _SIOWR('p', 65, int) +# define DSP_BIND_QUERY 0x00000000 +# define DSP_BIND_FRONT 0x00000001 +# define DSP_BIND_SURR 0x00000002 +# define DSP_BIND_CENTER_LFE 0x00000004 +# define DSP_BIND_HANDSET 0x00000008 +# define DSP_BIND_MIC 0x00000010 +# define DSP_BIND_MODEM1 0x00000020 +# define DSP_BIND_MODEM2 0x00000040 +# define DSP_BIND_I2S 0x00000080 +# define DSP_BIND_SPDIF 0x00000100 + +#define SNDCTL_DSP_SETSPDIF _SIOW ('p', 66, int) +#define SNDCTL_DSP_GETSPDIF _SIOR ('p', 67, int) +# define SPDIF_PRO 0x0001 +# define SPDIF_N_AUD 0x0002 +# define SPDIF_COPY 0x0004 +# define SPDIF_PRE 0x0008 +# define SPDIF_CC 0x07f0 +# define SPDIF_L 0x0800 +# define SPDIF_DRS 0x4000 +# define SPDIF_V 0x8000 + +/* + * Application's profile defines the way how playback underrun situations should be handled. + * + * APF_NORMAL (the default) and APF_NETWORK make the driver to cleanup the + * playback buffer whenever an underrun occurs. This consumes some time + * prevents looping the existing buffer. + * APF_CPUINTENS is intended to be set by CPU intensive applications which + * are likely to run out of time occasionally. In this mode the buffer cleanup is + * disabled which saves CPU time but also let's the previous buffer content to + * be played during the "pause" after the underrun. + */ +#define SNDCTL_DSP_PROFILE _SIOW ('p', 23, int) +#define APF_NORMAL 0 /* Normal applications */ +#define APF_NETWORK 1 /* Underruns probably caused by an "external" delay */ +#define APF_CPUINTENS 2 /* Underruns probably caused by "overheating" the CPU */ + +#define SOUND_PCM_READ_RATE _SIOR ('p', 2, int) +#define SOUND_PCM_READ_CHANNELS _SIOR ('p', 6, int) +#define SOUND_PCM_READ_BITS _SIOR ('p', 5, int) +#define SOUND_PCM_READ_FILTER _SIOR ('p', 7, int) + +/* Some alias names */ +#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SETFMT +#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED +#define SOUND_PCM_POST SNDCTL_DSP_POST +#define SOUND_PCM_RESET SNDCTL_DSP_RESET +#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC +#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE +#define SOUND_PCM_SETFRAGMENT SNDCTL_DSP_SETFRAGMENT +#define SOUND_PCM_GETFMTS SNDCTL_DSP_GETFMTS +#define SOUND_PCM_SETFMT SNDCTL_DSP_SETFMT +#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE +#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE +#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK +#define SOUND_PCM_GETCAPS SNDCTL_DSP_GETCAPS +#define SOUND_PCM_GETTRIGGER SNDCTL_DSP_GETTRIGGER +#define SOUND_PCM_SETTRIGGER SNDCTL_DSP_SETTRIGGER +#define SOUND_PCM_SETSYNCRO SNDCTL_DSP_SETSYNCRO +#define SOUND_PCM_GETIPTR SNDCTL_DSP_GETIPTR +#define SOUND_PCM_GETOPTR SNDCTL_DSP_GETOPTR +#define SOUND_PCM_MAPINBUF SNDCTL_DSP_MAPINBUF +#define SOUND_PCM_MAPOUTBUF SNDCTL_DSP_MAPOUTBUF + +/* + * ioctl calls to be used in communication with coprocessors and + * DSP chips. + */ + +typedef struct copr_buffer { + int command; /* Set to 0 if not used */ + int flags; +#define CPF_NONE 0x0000 +#define CPF_FIRST 0x0001 /* First block */ +#define CPF_LAST 0x0002 /* Last block */ + int len; + int offs; /* If required by the device (0 if not used) */ + + unsigned char data[4000]; /* NOTE! 4000 is not 4k */ + } copr_buffer; +/* XXX */ +#define _IOT__IOTBASE_copr_buffer _IOT (_IOTS (int), 4, _IOTS (char), 31, _IOTS (char), 3) + +typedef struct copr_debug_buf { + int command; /* Used internally. Set to 0 */ + int parm1; + int parm2; + int flags; + int len; /* Length of data in bytes */ + } copr_debug_buf; +#define _IOT__IOTBASE_copr_debug_buf _IOT (_IOTS (int), 5, 0, 0, 0, 0) + +typedef struct copr_msg { + int len; + unsigned char data[4000]; + } copr_msg; +/* XXX */ +#define _IOT__IOTBASE_copr_msg _IOT (_IOTS (int), 1, _IOTS (char), 31, _IOTS (char), 3) + +#define SNDCTL_COPR_RESET _SIO ('o', 0) +#define SNDCTL_COPR_LOAD _SIOWR('o', 1, copr_buffer) +#define SNDCTL_COPR_RDATA _SIOWR('o', 2, copr_debug_buf) +#define SNDCTL_COPR_RCODE _SIOWR('o', 3, copr_debug_buf) +#define SNDCTL_COPR_WDATA _SIOW ('o', 4, copr_debug_buf) +#define SNDCTL_COPR_WCODE _SIOW ('o', 5, copr_debug_buf) +#define SNDCTL_COPR_RUN _SIOWR('o', 6, copr_debug_buf) +#define SNDCTL_COPR_HALT _SIOWR('o', 7, copr_debug_buf) +#define SNDCTL_COPR_SENDMSG _SIOWR('o', 8, copr_msg) +#define SNDCTL_COPR_RCVMSG _SIOR ('o', 9, copr_msg) + +/********************************************* + * IOCTL commands for /dev/mixer + */ + +/* + * Mixer devices + * + * There can be up to 20 different analog mixer channels. The + * SOUND_MIXER_NRDEVICES gives the currently supported maximum. + * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells + * the devices supported by the particular mixer. + */ + +#define SOUND_MIXER_NRDEVICES 25 +#define SOUND_MIXER_VOLUME 0 +#define SOUND_MIXER_BASS 1 +#define SOUND_MIXER_TREBLE 2 +#define SOUND_MIXER_SYNTH 3 +#define SOUND_MIXER_PCM 4 +#define SOUND_MIXER_SPEAKER 5 +#define SOUND_MIXER_LINE 6 +#define SOUND_MIXER_MIC 7 +#define SOUND_MIXER_CD 8 +#define SOUND_MIXER_IMIX 9 /* Recording monitor */ +#define SOUND_MIXER_ALTPCM 10 +#define SOUND_MIXER_RECLEV 11 /* Recording level */ +#define SOUND_MIXER_IGAIN 12 /* Input gain */ +#define SOUND_MIXER_OGAIN 13 /* Output gain */ +/* + * The AD1848 codec and compatibles have three line level inputs + * (line, aux1 and aux2). Since each card manufacturer have assigned + * different meanings to these inputs, it's inpractical to assign + * specific meanings (line, cd, synth etc.) to them. + */ +#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ +#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */ +#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */ +#define SOUND_MIXER_DIGITAL1 17 /* Digital (input) 1 */ +#define SOUND_MIXER_DIGITAL2 18 /* Digital (input) 2 */ +#define SOUND_MIXER_DIGITAL3 19 /* Digital (input) 3 */ +#define SOUND_MIXER_PHONEIN 20 /* Phone input */ +#define SOUND_MIXER_PHONEOUT 21 /* Phone output */ +#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */ +#define SOUND_MIXER_RADIO 23 /* Radio in */ +#define SOUND_MIXER_MONITOR 24 /* Monitor (usually mic) volume */ + +/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */ +/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ +#define SOUND_ONOFF_MIN 28 +#define SOUND_ONOFF_MAX 30 + +/* Note! Number 31 cannot be used since the sign bit is reserved */ +#define SOUND_MIXER_NONE 31 + +/* + * The following unsupported macros are no longer functional. + * Use SOUND_MIXER_PRIVATE# macros in future. + */ +#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE +#define SOUND_MIXER_MUTE SOUND_MIXER_NONE +#define SOUND_MIXER_LOUD SOUND_MIXER_NONE + + +#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ + "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ + "Line1", "Line2", "Line3", "Digital1", "Digital2", "Digital3", \ + "PhoneIn", "PhoneOut", "Video", "Radio", "Monitor"} + +#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ + "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \ + "line1", "line2", "line3", "dig1", "dig2", "dig3", \ + "phin", "phout", "video", "radio", "monitor"} + +/* Device bitmask identifiers */ + +#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */ +#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */ +#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */ +#define SOUND_MIXER_CAPS 0xfc +# define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */ +#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ +#define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */ +#define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */ + +/* Device mask bits */ + +#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) +#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) +#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) +#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) +#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM) +#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER) +#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE) +#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC) +#define SOUND_MASK_CD (1 << SOUND_MIXER_CD) +#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) +#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) +#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) +#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN) +#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN) +#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1) +#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) +#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) +#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1) +#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2) +#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3) +#define SOUND_MASK_PHONEIN (1 << SOUND_MIXER_PHONEIN) +#define SOUND_MASK_PHONEOUT (1 << SOUND_MIXER_PHONEOUT) +#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO) +#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO) +#define SOUND_MASK_MONITOR (1 << SOUND_MIXER_MONITOR) + +/* Obsolete macros */ +#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) +#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) +#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) + +#define MIXER_READ(dev) _SIOR('r', dev, int) +#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS) +#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM) +#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE) +#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC) +#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD) +#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) +#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) +#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) +#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) +#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) +#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) +#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK) +#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS) +#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS) + +#define MIXER_WRITE(dev) _SIOWR('r', dev, int) +#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS) +#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM) +#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE) +#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC) +#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD) +#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) +#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) +#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) +#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) +#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) + +typedef struct mixer_info +{ + char id[16]; +/* XXX */ + char name[15]; + int modify_counter; + int fillers[10]; +} mixer_info; +#define _IOT__IOTBASE_mixer_info _IOT (_IOTS (char), 31, _IOTS (int), 11, 0, 0) + +typedef struct _old_mixer_info /* Obsolete */ +{ + char id[16]; + char name[32]; +} _old_mixer_info; +#define _IOT__IOTBASE__old_mixer_info _IOT (_IOTS (char), 17, _IOTS (char), 31, 0, 0) + +#define SOUND_MIXER_INFO _SIOR ('r', 101, mixer_info) +#define SOUND_OLD_MIXER_INFO _SIOR ('r', 101, _old_mixer_info) + +/* + * A mechanism for accessing "proprietary" mixer features. This method + * permits passing 128 bytes of arbitrary data between a mixer application + * and the mixer driver. Interpretation of the record is defined by + * the particular mixer driver. + */ +typedef unsigned char mixer_record[128]; +/* XXX */ +#define _IOT__IOTBASE_mixer_record _IOT (_IOTS (char), 31, _IOTS (char), 31, _IOTS (char), 3) + +#define SOUND_MIXER_ACCESS _SIOWR('r', 102, mixer_record) + +/* + * Two ioctls for special souncard function + */ +#define SOUND_MIXER_AGC _SIOWR('r', 103, int) +#define SOUND_MIXER_3DSE _SIOWR('r', 104, int) + +/* + * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers. + * These features can be used when accessing device specific features. + */ +#define SOUND_MIXER_PRIVATE1 _SIOWR('r', 111, int) +#define SOUND_MIXER_PRIVATE2 _SIOWR('r', 112, int) +#define SOUND_MIXER_PRIVATE3 _SIOWR('r', 113, int) +#define SOUND_MIXER_PRIVATE4 _SIOWR('r', 114, int) +#define SOUND_MIXER_PRIVATE5 _SIOWR('r', 115, int) + +/* + * SOUND_MIXER_GETLEVELS and SOUND_MIXER_SETLEVELS calls can be used + * for querying current mixer settings from the driver and for loading + * default volume settings _prior_ activating the mixer (loading + * doesn't affect current state of the mixer hardware). These calls + * are for internal use only. + */ + +typedef struct mixer_vol_table { + char name[31]; + int num; /* Index to volume table */ + int levels[32]; +} mixer_vol_table; +#define _IOT__IOTBASE_mixer_vol_table _IOT (_IOTS (char), 31, _IOTS (int), 31, _IOTS (int), 2) + +#define SOUND_MIXER_GETLEVELS _SIOWR('r', 116, mixer_vol_table) +#define SOUND_MIXER_SETLEVELS _SIOWR('r', 117, mixer_vol_table) + +/* + * An ioctl for identifying the driver version. It will return value + * of the SOUND_VERSION macro used when compiling the driver. + * This call was introduced in OSS version 3.6 and it will not work + * with earlier versions (returns EINVAL). + */ +#define OSS_GETVERSION _SIOR ('r', 118, int) + +/* + * Level 2 event types for /dev/sequencer + */ + +/* + * The 4 most significant bits of byte 0 specify the class of + * the event: + * + * 0x8X = system level events, + * 0x9X = device/port specific events, event[1] = device/port, + * The last 4 bits give the subtype: + * 0x02 = Channel event (event[3] = chn). + * 0x01 = note event (event[4] = note). + * (0x01 is not used alone but always with bit 0x02). + * event[2] = MIDI message code (0x80=note off etc.) + * + */ + +#define EV_SEQ_LOCAL 0x80 +#define EV_TIMING 0x81 +#define EV_CHN_COMMON 0x92 +#define EV_CHN_VOICE 0x93 +#define EV_SYSEX 0x94 +/* + * Event types 200 to 220 are reserved for application use. + * These numbers will not be used by the driver. + */ + +/* + * Events for event type EV_CHN_VOICE + */ + +#define MIDI_NOTEOFF 0x80 +#define MIDI_NOTEON 0x90 +#define MIDI_KEY_PRESSURE 0xA0 + +/* + * Events for event type EV_CHN_COMMON + */ + +#define MIDI_CTL_CHANGE 0xB0 +#define MIDI_PGM_CHANGE 0xC0 +#define MIDI_CHN_PRESSURE 0xD0 +#define MIDI_PITCH_BEND 0xE0 + +#define MIDI_SYSTEM_PREFIX 0xF0 + +/* + * Timer event types + */ +#define TMR_WAIT_REL 1 /* Time relative to the prev time */ +#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ +#define TMR_STOP 3 +#define TMR_START 4 +#define TMR_CONTINUE 5 +#define TMR_TEMPO 6 +#define TMR_ECHO 8 +#define TMR_CLOCK 9 /* MIDI clock */ +#define TMR_SPP 10 /* Song position pointer */ +#define TMR_TIMESIG 11 /* Time signature */ + +/* + * Local event types + */ +#define LOCL_STARTAUDIO 1 + +#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) +/* + * Some convenience macros to simplify programming of the + * /dev/sequencer interface + * + * These macros define the API which should be used when possible. + */ +#define SEQ_DECLAREBUF() SEQ_USE_EXTBUF() + +void seqbuf_dump(void); /* This function must be provided by programs */ + +extern int OSS_init(int seqfd, int buflen); +extern void OSS_seqbuf_dump(int fd, unsigned char *buf, int buflen); +extern void OSS_seq_advbuf(int len, int fd, unsigned char *buf, int buflen); +extern void OSS_seq_needbuf(int len, int fd, unsigned char *buf, int buflen); +extern void OSS_patch_caching(int dev, int chn, int patch, + int fd, unsigned char *buf, int buflen); +extern void OSS_drum_caching(int dev, int chn, int patch, + int fd, unsigned char *buf, int buflen); +extern void OSS_write_patch(int fd, unsigned char *buf, int len); +extern int OSS_write_patch2(int fd, unsigned char *buf, int len); + +#define SEQ_PM_DEFINES int __foo_bar___ +#ifdef OSSLIB +# define SEQ_USE_EXTBUF() \ + extern unsigned char *_seqbuf; \ + extern int _seqbuflen;extern int _seqbufptr +# define SEQ_DEFINEBUF(len) SEQ_USE_EXTBUF();static int _requested_seqbuflen=len +# define _SEQ_ADVBUF(len) OSS_seq_advbuf(len, seqfd, _seqbuf, _seqbuflen) +# define _SEQ_NEEDBUF(len) OSS_seq_needbuf(len, seqfd, _seqbuf, _seqbuflen) +# define SEQ_DUMPBUF() OSS_seqbuf_dump(seqfd, _seqbuf, _seqbuflen) + +# define SEQ_LOAD_GMINSTR(dev, instr) \ + OSS_patch_caching(dev, -1, instr, seqfd, _seqbuf, _seqbuflen) +# define SEQ_LOAD_GMDRUM(dev, drum) \ + OSS_drum_caching(dev, -1, drum, seqfd, _seqbuf, _seqbuflen) +#else /* !OSSLIB */ + +# define SEQ_LOAD_GMINSTR(dev, instr) +# define SEQ_LOAD_GMDRUM(dev, drum) + +# define SEQ_USE_EXTBUF() \ + extern unsigned char _seqbuf[]; \ + extern int _seqbuflen;extern int _seqbufptr + +#ifndef USE_SIMPLE_MACROS +/* Sample seqbuf_dump() implementation: + * + * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes + * + * int seqfd; -- The file descriptor for /dev/sequencer. + * + * void + * seqbuf_dump () + * { + * if (_seqbufptr) + * if (write (seqfd, _seqbuf, _seqbufptr) == -1) + * { + * perror ("write /dev/sequencer"); + * exit (-1); + * } + * _seqbufptr = 0; + * } + */ + +#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0 +#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump() +#define _SEQ_ADVBUF(len) _seqbufptr += len +#define SEQ_DUMPBUF seqbuf_dump +#else +/* + * This variation of the sequencer macros is used just to format one event + * using fixed buffer. + * + * The program using the macro library must define the following macros before + * using this library. + * + * #define _seqbuf name of the buffer (unsigned char[]) + * #define _SEQ_ADVBUF(len) If the applic needs to know the exact + * size of the event, this macro can be used. + * Otherwise this must be defined as empty. + * #define _seqbufptr Define the name of index variable or 0 if + * not required. + */ +#define _SEQ_NEEDBUF(len) /* empty */ +#endif +#endif /* !OSSLIB */ + +#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (mode);\ + _seqbuf[_seqbufptr+4] = 0;\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +/* + * Midi voice messages + */ + +#define _CHN_VOICE(dev, event, chn, note, parm) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_VOICE;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (note);\ + _seqbuf[_seqbufptr+5] = (parm);\ + _seqbuf[_seqbufptr+6] = (0);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_START_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol) + +#define SEQ_STOP_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol) + +#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \ + _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure) + +/* + * Midi channel messages + */ + +#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_COMMON;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (p1);\ + _seqbuf[_seqbufptr+5] = (p2);\ + *(short *)&_seqbuf[_seqbufptr+6] = (w14);\ + _SEQ_ADVBUF(8);} +/* + * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits + * sending any MIDI bytes but it's absolutely not possible. Trying to do + * so _will_ cause problems with MPU401 intelligent mode). + * + * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be + * sent by calling SEQ_SYSEX() several times (there must be no other events + * between them). First sysex fragment must have 0xf0 in the first byte + * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte + * between these sysex start and end markers cannot be larger than 0x7f. Also + * lengths of each fragments (except the last one) must be 6. + * + * Breaking the above rules may work with some MIDI ports but is likely to + * cause fatal problems with some other devices (such as MPU401). + */ +#define SEQ_SYSEX(dev, buf, len) \ + {int ii, ll=(len); \ + unsigned char *bufp=buf;\ + if (ll>6)ll=6;\ + _SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_SYSEX;\ + _seqbuf[_seqbufptr+1] = (dev);\ + for(ii=0;ii<ll;ii++)\ + _seqbuf[_seqbufptr+ii+2] = bufp[ii];\ + for(ii=ll;ii<6;ii++)\ + _seqbuf[_seqbufptr+ii+2] = 0xff;\ + _SEQ_ADVBUF(8);} + +#define SEQ_CHN_PRESSURE(dev, chn, pressure) \ + _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0) + +#define SEQ_SET_PATCH SEQ_PGM_CHANGE +#ifdef OSSLIB +# define SEQ_PGM_CHANGE(dev, chn, patch) \ + {OSS_patch_caching(dev, chn, patch, seqfd, _seqbuf, _seqbuflen); \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0);} +#else +# define SEQ_PGM_CHANGE(dev, chn, patch) \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0) +#endif + +#define SEQ_CONTROL(dev, chn, controller, value) \ + _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value) + +#define SEQ_BENDER(dev, chn, value) \ + _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value) + + +#define SEQ_V2_X_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (controller);\ + _seqbuf[_seqbufptr+5] = ((value)&0xff);\ + _seqbuf[_seqbufptr+6] = ((value>>8)&0xff);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} +/* + * The following 5 macros are incorrectly implemented and obsolete. + * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead. + */ +#define SEQ_PITCHBEND(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) +#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) +#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128) +#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100) +#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) + +/* + * Timing and syncronization macros + */ + +#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_TIMING; \ + _seqbuf[_seqbufptr+1] = (ev); \ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ + _SEQ_ADVBUF(8);} + +#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0) +#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0) +#define SEQ_CONTINUE_TIMER() _TIMER_EVENT(TMR_CONTINUE, 0) +#define SEQ_WAIT_TIME(ticks) _TIMER_EVENT(TMR_WAIT_ABS, ticks) +#define SEQ_DELTA_TIME(ticks) _TIMER_EVENT(TMR_WAIT_REL, ticks) +#define SEQ_ECHO_BACK(key) _TIMER_EVENT(TMR_ECHO, key) +#define SEQ_SET_TEMPO(value) _TIMER_EVENT(TMR_TEMPO, value) +#define SEQ_SONGPOS(pos) _TIMER_EVENT(TMR_SPP, pos) +#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig) + +/* + * Local control events + */ + +#define _LOCAL_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \ + _seqbuf[_seqbufptr+1] = (ev); \ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ + _SEQ_ADVBUF(8);} + +#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask) +/* + * Events for the level 1 interface only + */ + +#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\ + _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\ + _seqbuf[_seqbufptr+1] = (byte);\ + _seqbuf[_seqbufptr+2] = (device);\ + _seqbuf[_seqbufptr+3] = 0;\ + _SEQ_ADVBUF(4);} + +/* + * Patch loading. + */ +#ifdef OSSLIB +# define SEQ_WRPATCH(patchx, len) \ + OSS_write_patch(seqfd, (char*)(patchx), len) +# define SEQ_WRPATCH2(patchx, len) \ + OSS_write_patch2(seqfd, (char*)(patchx), len) +#else +# define SEQ_WRPATCH(patchx, len) \ + {if (_seqbufptr) SEQ_DUMPBUF();\ + if (write(seqfd, (char*)(patchx), len)==-1) \ + perror("Write patch: /dev/sequencer");} +# define SEQ_WRPATCH2(patchx, len) \ + (SEQ_DUMPBUF(), write(seqfd, (char*)(patchx), len)) +#endif + +#endif +#endif /* sys/soundcard.h */ diff --git a/debian/make-new-orig.sh b/debian/make-new-orig.sh new file mode 100755 index 00000000..8f427623 --- /dev/null +++ b/debian/make-new-orig.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +if [ -z $1 ]; then + echo "Please provide the directory to tar up as an argument" + exit 1 +fi + +TARBALL=$(echo $1 | tr - _).orig.tar.gz + +tar -czvf $TARBALL --exclude=debian $1 + diff --git a/debian/make-new-tarball.sh b/debian/make-new-tarball.sh new file mode 100755 index 00000000..5af64b97 --- /dev/null +++ b/debian/make-new-tarball.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +if [ -z $1 ]; then + echo "Please provide the directory to tar up as an argument" + exit 1 +fi + +BASENAME=$(basename $1) +DIRNAME=$(dirname $1) + +tar -czvf hurd.tgz \ + --exclude=.git --exclude=.gitignore --exclude=debian \ + -C $DIRNAME $BASENAME + diff --git a/debian/patches/MAKEDEV.patch b/debian/patches/MAKEDEV.patch new file mode 100644 index 00000000..8f130d0c --- /dev/null +++ b/debian/patches/MAKEDEV.patch @@ -0,0 +1,60 @@ +commit 62e4f1a11b4598daa4a22fe3b868fde3c6fa818e +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Mon Jan 11 03:03:08 2010 +0100 + + Make MAKEDEV bash-free + + * sutils/MAKEDEV.sh (cmd, st, lose, mkdev): Remove function, add + (). + (mkdev): Use ${I#???} instead of ${I:3}. + +--- + MAKEDEV.sh | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sutils/MAKEDEV.sh b/sutils/MAKEDEV.sh +index 260e93b..4277b05 100644 +--- a/sutils/MAKEDEV.sh ++++ b/sutils/MAKEDEV.sh +@@ -51,12 +51,12 @@ case "$#" in 0) + exit 1;; + esac + +-function cmd { ++cmd() { + eval $ECHO "$@" + eval $EXEC "$@" + } + +-function st { ++st() { + local NODE="$1" + local OWNER="$2" + local PERM="$3" +@@ -68,7 +68,7 @@ function st { + fi + } + +-function lose { ++lose() { + local line + for line; do + echo 1>&2 "$0: $line" +@@ -76,7 +76,7 @@ function lose { + exit 1 + } + +-function mkdev { ++mkdev() { + local I + for I; do + case $I in +@@ -120,7 +120,7 @@ function mkdev { + # ptys + [pt]ty[pqrstuvwxyzPQRS]?) + # Make one pty, both the master and slave halves. +- local id="${I:3}" ++ local id="${I#???}" + st pty$id root 666 /hurd/term ${DEVDIR}/pty$id \ + pty-master ${DEVDIR}/tty$id + st tty$id root 666 /hurd/term ${DEVDIR}/tty$id \ diff --git a/debian/patches/console_current_vcs.patch b/debian/patches/console_current_vcs.patch new file mode 100644 index 00000000..c905677f --- /dev/null +++ b/debian/patches/console_current_vcs.patch @@ -0,0 +1,61 @@ +commit 9291cd3fa6a76e999bc8dab25e9d5dc492403571 +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Sun Oct 25 20:55:04 2009 +0100 + + Fix current_vcs driver load + + * console-client/current-vcs.c (vcs_repeat_init): Rename function into... + (current_vcs_init): ... this. + (vcs_repeat_start): Rename function into... + (current_vcs_start): ... this. + (vcs_repeat_fini): Rename function into... + (current_vcs_fini): ... this. + +--- + console-client/current-vcs.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/console-client/current-vcs.c ++++ b/console-client/current-vcs.c +@@ -167,7 +167,7 @@ static struct argp argp = {options, pars + + /* Initialize the current VCS driver. */ + static error_t +-vcs_repeat_init (void **handle, int no_exit, int argc, char *argv[], int *next) ++current_vcs_init (void **handle, int no_exit, int argc, char *argv[], int *next) + { + error_t err; + int pos = 1; +@@ -184,7 +184,7 @@ vcs_repeat_init (void **handle, int no_e + } + + static error_t +-vcs_repeat_start (void *handle) ++current_vcs_start (void *handle) + { + error_t err; + +@@ -206,7 +206,7 @@ vcs_repeat_start (void *handle) + } + + static error_t +-vcs_repeat_fini (void *handle, int force) ++current_vcs_fini (void *handle, int force) + { + console_unregister_consnode (vcs_node); + console_destroy_consnode (vcs_node); +@@ -214,10 +214,10 @@ vcs_repeat_fini (void *handle, int force + } + + +-struct driver_ops driver_vcs_repeat_ops = ++struct driver_ops driver_current_vcs_ops = + { +- vcs_repeat_init, +- vcs_repeat_start, +- vcs_repeat_fini ++ current_vcs_init, ++ current_vcs_start, ++ current_vcs_fini + }; + diff --git a/debian/patches/console_utf-8.patch b/debian/patches/console_utf-8.patch new file mode 100644 index 00000000..663e21bd --- /dev/null +++ b/debian/patches/console_utf-8.patch @@ -0,0 +1,19 @@ +2006-08-26 Michael Banck <mbanck@debian.org> + + * console.c (DEFAULT_ENCODING): Set to UTF-8. + +--- + console/console.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/console/console.c ++++ b/console/console.c +@@ -58,7 +58,7 @@ int netfs_maxsymlinks = 16; /* Arbitrary + /* Handy source of time. */ + volatile struct mapped_time_value *console_maptime; + +-#define DEFAULT_ENCODING "ISO-8859-1" ++#define DEFAULT_ENCODING "UTF-8" + #define DEFAULT_INTENSITY CONS_ATTR_INTENSITY_NORMAL + #define DEFAULT_UNDERLINED 0 + #define DEFAULT_BLINKING 0 diff --git a/debian/patches/dir_acces_fix.patch b/debian/patches/dir_acces_fix.patch new file mode 100644 index 00000000..964b39a5 --- /dev/null +++ b/debian/patches/dir_acces_fix.patch @@ -0,0 +1,15 @@ +--- + libfshelp/perms-access.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/libfshelp/perms-access.c ++++ b/libfshelp/perms-access.c +@@ -30,7 +30,7 @@ fshelp_access (struct stat *st, int op, + { + int gotit; + if (idvec_contains (user->uids, 0)) +- gotit = (op != S_IEXEC) || (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)); ++ gotit = (op != S_IEXEC) || !S_ISREG(st->st_mode) || (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)); + else if (user->uids->num == 0 && (st->st_mode & S_IUSEUNK)) + gotit = st->st_mode & (op << S_IUNKSHIFT); + else if (!fshelp_isowner (st, user)) diff --git a/debian/patches/diskfs_no_inherit_dir_group.patch b/debian/patches/diskfs_no_inherit_dir_group.patch new file mode 100644 index 00000000..8d17f3e0 --- /dev/null +++ b/debian/patches/diskfs_no_inherit_dir_group.patch @@ -0,0 +1,29 @@ +Follow POSIX rules for gid of new nodes. +--- + opts-common.c | 2 +- + libdiskfs/init-init.c | 3 +++ + 2 file changed, 4 insertion(+), 1 deletion(-) + +--- a/libdiskfs/init-init.c ++++ b/libdiskfs/init-init.c +@@ -57,6 +57,9 @@ diskfs_init_diskfs (void) + { + error_t err; + ++ /* See `node-create.c'. */ ++ _diskfs_no_inherit_dir_group = 1; ++ + if (diskfs_boot_filesystem ()) + /* This is a boot filesystem, we have to do some things specially. */ + { +--- a/libdiskfs/opts-common.c ++++ b/libdiskfs/opts-common.c +@@ -52,7 +52,7 @@ const struct argp_option diskfs_common_options[] = + {"nogrpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"sysvgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"inherit-dir-group", OPT_INHERIT_DIR_GROUP, 0, 0, +- "Create new nodes with gid of parent dir (default)"}, ++ "Create new nodes with gid of parent dir"}, + {"grpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"bsdgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {0, 0} diff --git a/debian/patches/exec_fix.patch b/debian/patches/exec_fix.patch new file mode 100644 index 00000000..2d53678a --- /dev/null +++ b/debian/patches/exec_fix.patch @@ -0,0 +1,29 @@ +Fixes long-standing random hang of exec. + +2009-05-25 Samuel Thibault <samuel.thibault@ens-lyon.org> + + * exec.c (finish): Set FILE_DATA and MAP_BUFFER members of E to NULL + after freeing them. + +--- + exec/exec.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/exec/exec.c ++++ b/exec/exec.c +@@ -1008,10 +1008,13 @@ finish (struct execdata *e, int dealloc_ + #ifdef EXECDATA_STREAM + fclose (&e->stream); + #else +- if (e->file_data != NULL) ++ if (e->file_data != NULL) { + free (e->file_data); +- else if (map_buffer (e) != NULL) ++ 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) diff --git a/debian/patches/ext2fs_large_stores.patch b/debian/patches/ext2fs_large_stores.patch new file mode 100644 index 00000000..7a78c4b7 --- /dev/null +++ b/debian/patches/ext2fs_large_stores.patch @@ -0,0 +1,2244 @@ +Support for >2GB volumes +--- + console/pager.c | 10 + ext2fs/balloc.c | 57 +++-- + ext2fs/ext2_fs.h | 3 + ext2fs/ext2fs.c | 8 + ext2fs/ext2fs.h | 145 +++++++++++-- + ext2fs/getblk.c | 31 +- + ext2fs/hyper.c | 34 ++- + ext2fs/ialloc.c | 41 +++ + ext2fs/inode.c | 58 +++-- + ext2fs/pager.c | 497 +++++++++++++++++++++++++++++++++++++++++++---- + ext2fs/pokel.c | 41 +++ + ext2fs/truncate.c | 11 - + fatfs/pager.c | 11 - + isofs/pager.c | 12 - + libdiskfs/disk-pager.c | 6 + libdiskfs/diskfs-pager.h | 3 + libpager/data-request.c | 17 - + libpager/data-return.c | 78 +++++-- + libpager/pager-create.c | 4 + libpager/pager.h | 29 ++ + libpager/priv.h | 1 + storeio/pager.c | 9 + tmpfs/pager-stubs.c | 8 + ufs/pager.c | 11 - + 24 files changed, 940 insertions(+), 185 deletions(-) + +--- a/console/pager.c ++++ b/console/pager.c +@@ -94,6 +94,14 @@ pager_unlock_page (struct user_pager_inf + } + + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ assert (!"unrequested notification on eviction"); ++} ++ ++ + /* Tell how big the file is. */ + error_t + pager_report_extent (struct user_pager_info *upi, +@@ -159,7 +167,7 @@ user_pager_create (struct user_pager *us + + /* XXX Are the values 1 and MEMORY_OBJECT_COPY_DELAY correct? */ + user_pager->pager = pager_create (upi, pager_bucket, +- 1, MEMORY_OBJECT_COPY_DELAY); ++ 1, MEMORY_OBJECT_COPY_DELAY, 0); + if (!user_pager->pager) + { + free (upi); +--- a/ext2fs/balloc.c ++++ b/ext2fs/balloc.c +@@ -92,7 +92,7 @@ ext2_free_blocks (block_t block, unsigne + block, count); + } + gdp = group_desc (block_group); +- bh = bptr (gdp->bg_block_bitmap); ++ bh = disk_cache_block_ref (gdp->bg_block_bitmap); + + if (in_range (gdp->bg_block_bitmap, block, gcount) || + in_range (gdp->bg_inode_bitmap, block, gcount) || +@@ -114,6 +114,7 @@ ext2_free_blocks (block_t block, unsigne + } + + record_global_poke (bh); ++ disk_cache_block_ref_ptr (gdp); + record_global_poke (gdp); + + block += gcount; +@@ -139,7 +140,7 @@ ext2_new_block (block_t goal, + block_t prealloc_goal, + block_t *prealloc_count, block_t *prealloc_block) + { +- char *bh; ++ char *bh = 0; + char *p, *r; + int i, j, k, tmp; + unsigned long lmap; +@@ -164,9 +165,10 @@ ext2_new_block (block_t goal, + + ext2_debug ("goal=%u", goal); + +-repeat: ++ repeat: ++ assert (! bh); + /* +- * First, test whether the goal block is free. ++ * First, test whether the goal block is free. + */ + if (goal < sblock->s_first_data_block || goal >= sblock->s_blocks_count) + goal = sblock->s_first_data_block; +@@ -179,7 +181,7 @@ repeat: + if (j) + goal_attempts++; + #endif +- bh = bptr (gdp->bg_block_bitmap); ++ bh = disk_cache_block_ref (gdp->bg_block_bitmap); + + ext2_debug ("goal is at %d:%d", i, j); + +@@ -194,8 +196,8 @@ repeat: + if (j) + { + /* +- * The goal was occupied; search forward for a free +- * block within the next 32 blocks ++ * The goal was occupied; search forward for a free ++ * block within the next 32 blocks + */ + lmap = ((((unsigned long *) bh)[j >> 5]) >> + ((j & 31) + 1)); +@@ -242,13 +244,16 @@ repeat: + j = k; + goto got_block; + } ++ ++ disk_cache_block_deref (bh); ++ bh = 0; + } + + ext2_debug ("bit not found in block group %d", i); + + /* +- * Now search the rest of the groups. We assume that +- * i and gdp correctly point to the last group visited. ++ * Now search the rest of the groups. We assume that ++ * i and gdp correctly point to the last group visited. + */ + for (k = 0; k < groups_count; k++) + { +@@ -264,7 +269,8 @@ repeat: + spin_unlock (&global_lock); + return 0; + } +- bh = bptr (gdp->bg_block_bitmap); ++ assert (! bh); ++ bh = disk_cache_block_ref (gdp->bg_block_bitmap); + r = memscan (bh, 0, sblock->s_blocks_per_group >> 3); + j = (r - bh) << 3; + if (j < sblock->s_blocks_per_group) +@@ -274,21 +280,25 @@ repeat: + sblock->s_blocks_per_group); + if (j >= sblock->s_blocks_per_group) + { ++ disk_cache_block_deref (bh); ++ bh = 0; + ext2_error ("free blocks count corrupted for block group %d", i); + spin_unlock (&global_lock); + return 0; + } + +-search_back: ++ search_back: ++ assert (bh); + /* +- * We have succeeded in finding a free byte in the block +- * bitmap. Now search backwards up to 7 bits to find the +- * start of this group of free blocks. ++ * We have succeeded in finding a free byte in the block ++ * bitmap. Now search backwards up to 7 bits to find the ++ * start of this group of free blocks. + */ + for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh); k++, j--); + +-got_block: +- ++ got_block: ++ assert (bh); ++ + ext2_debug ("using block group %d (%d)", i, gdp->bg_free_blocks_count); + + tmp = j + i * sblock->s_blocks_per_group + sblock->s_first_data_block; +@@ -301,6 +311,8 @@ got_block: + if (set_bit (j, bh)) + { + ext2_warning ("bit already set for block %d", j); ++ disk_cache_block_deref (bh); ++ bh = 0; + goto repeat; + } + +@@ -317,7 +329,7 @@ got_block: + ext2_debug ("found bit %d", j); + + /* +- * Do block preallocation now if required. ++ * Do block preallocation now if required. + */ + #ifdef EXT2_PREALLOCATE + if (prealloc_goal) +@@ -348,6 +360,7 @@ got_block: + j = tmp; + + record_global_poke (bh); ++ bh = 0; + + if (j >= sblock->s_blocks_count) + { +@@ -360,12 +373,14 @@ got_block: + j, goal_hits, goal_attempts); + + gdp->bg_free_blocks_count--; ++ disk_cache_block_ref_ptr (gdp); + record_global_poke (gdp); + + sblock->s_free_blocks_count--; + sblock_dirty = 1; + + sync_out: ++ assert (! bh); + spin_unlock (&global_lock); + alloc_sync (0); + +@@ -387,9 +402,12 @@ ext2_count_free_blocks () + gdp = NULL; + for (i = 0; i < groups_count; i++) + { ++ void *bh; + gdp = group_desc (i); + desc_count += gdp->bg_free_blocks_count; +- x = count_free (bptr (gdp->bg_block_bitmap), block_size); ++ bh = disk_cache_block_ref (gdp->bg_block_bitmap); ++ x = count_free (bh, block_size); ++ disk_cache_block_deref (bh); + printf ("group %d: stored = %d, counted = %lu", + i, gdp->bg_free_blocks_count, x); + bitmap_count += x; +@@ -450,7 +468,7 @@ ext2_check_blocks_bitmap () + + gdp = group_desc (i); + desc_count += gdp->bg_free_blocks_count; +- bh = bptr (gdp->bg_block_bitmap); ++ bh = disk_cache_block_ref (gdp->bg_block_bitmap); + + if (!EXT2_HAS_RO_COMPAT_FEATURE (sblock, + EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) +@@ -476,6 +494,7 @@ ext2_check_blocks_bitmap () + ext2_error ("block #%d of the inode table in group %d is marked free", j, i); + + x = count_free (bh, block_size); ++ disk_cache_block_deref (bh); + if (gdp->bg_free_blocks_count != x) + ext2_error ("wrong free blocks count for group %d," + " stored = %d, counted = %lu", +--- a/ext2fs/ext2_fs.h ++++ b/ext2fs/ext2_fs.h +@@ -25,7 +25,8 @@ + /* + * Define EXT2FS_DEBUG to produce debug messages + */ +-#undef EXT2FS_DEBUG ++/* #undef EXT2FS_DEBUG */ ++#define EXT2FS_DEBUG + + /* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files +--- a/ext2fs/ext2fs.c ++++ b/ext2fs/ext2fs.c +@@ -106,7 +106,7 @@ parse_opt (int key, char *arg, struct ar + if (values == 0) + return ENOMEM; + state->hook = values; +- bzero (values, sizeof *values); ++ memset (values, 0, sizeof *values); + values->sb_block = SBLOCK_BLOCK; + break; + +@@ -181,9 +181,9 @@ main (int argc, char **argv) + /* Map the entire disk. */ + create_disk_pager (); + +- pokel_init (&global_pokel, diskfs_disk_pager, disk_image); ++ pokel_init (&global_pokel, diskfs_disk_pager, disk_cache); + +- get_hypermetadata(); ++ map_hypermetadata (); + + inode_init (); + +@@ -211,6 +211,8 @@ diskfs_reload_global_state () + { + pokel_flush (&global_pokel); + pager_flush (diskfs_disk_pager, 1); ++ sblock = 0; + get_hypermetadata (); ++ map_hypermetadata (); + return 0; + } +--- a/ext2fs/ext2fs.h ++++ b/ext2fs/ext2fs.h +@@ -23,7 +23,9 @@ + #include <hurd/pager.h> + #include <hurd/fshelp.h> + #include <hurd/iohelp.h> ++#include <hurd/store.h> + #include <hurd/diskfs.h> ++#include <hurd/ihash.h> + #include <assert.h> + #include <rwlock.h> + #include <sys/mman.h> +@@ -186,6 +188,8 @@ struct user_pager_info + /* ---------------------------------------------------------------- */ + /* pager.c */ + ++#define DISK_CACHE_BLOCKS 65536 ++ + #include <hurd/diskfs-pager.h> + + /* Set up the disk pager. */ +@@ -209,10 +213,54 @@ extern struct store *store; + /* What the user specified. */ + extern struct store_parsed *store_parsed; + +-/* Mapped image of the disk. */ +-extern void *disk_image; ++/* Mapped image of cached blocks of the disk. */ ++extern void *disk_cache; ++extern store_offset_t disk_cache_size; ++extern int disk_cache_blocks; ++ ++#define DC_INCORE 0x01 /* Not in core. */ ++#define DC_UNTOUCHED 0x02 /* Not touched by disk_pager_read_paged ++ or disk_cache_block_ref. */ ++#define DC_FIXED 0x04 /* Must not be re-associated. */ ++ ++/* Flags that forbid re-association of page. DC_UNTOUCHED is included ++ because this flag is used only when page is already to be ++ re-associated, so it's not good candidate for another ++ remapping. */ ++#define DC_DONT_REUSE (DC_INCORE | DC_UNTOUCHED | DC_FIXED) ++ ++#define DC_NO_BLOCK ((block_t) -1L) ++ ++#ifndef NDEBUG ++#define DISK_CACHE_LAST_READ_XOR 0xDEADBEEF ++#endif + +-/* Our in-core copy of the super-block (pointer into the disk_image). */ ++/* Disk cache blocks' meta info. */ ++struct disk_cache_info ++{ ++ block_t block; ++ uint16_t flags; ++ uint16_t ref_count; ++#ifndef NDEBUG ++ block_t last_read, last_read_xor; ++#endif ++}; ++ ++/* block num --> pointer to in-memory block */ ++extern hurd_ihash_t disk_cache_bptr; ++/* Metadata about cached block. */ ++extern struct disk_cache_info *disk_cache_info; ++/* Lock for these mappings */ ++extern struct mutex disk_cache_lock; ++/* Fired when a re-association is done. */ ++extern struct condition disk_cache_reassociation; ++ ++void *disk_cache_block_ref (block_t block); ++void disk_cache_block_ref_ptr (void *ptr); ++void disk_cache_block_deref (void *ptr); ++int disk_cache_block_is_ref (block_t block); ++ ++/* Our in-core copy of the super-block (pointer into the disk_cache). */ + struct ext2_super_block *sblock; + /* True if sblock has been modified. */ + int sblock_dirty; +@@ -242,6 +290,9 @@ vm_address_t zeroblock; + + /* Get the superblock from the disk, & setup various global info from it. */ + void get_hypermetadata (); ++ ++/* Map `sblock' and `group_desc_image' pointers to disk cache. */ ++void map_hypermetadata (); + + /* ---------------------------------------------------------------- */ + /* Random stuff calculated from the super block. */ +@@ -265,21 +316,51 @@ spin_lock_t generation_lock; + unsigned long next_generation; + + /* ---------------------------------------------------------------- */ +-/* Functions for looking inside disk_image */ ++/* Functions for looking inside disk_cache */ + +-#define trunc_block(offs) (((offs) >> log2_block_size) << log2_block_size) ++#define trunc_block(offs) \ ++ ((off_t) ((offs) >> log2_block_size) << log2_block_size) + #define round_block(offs) \ +- ((((offs) + block_size - 1) >> log2_block_size) << log2_block_size) ++ ((off_t) (((offs) + block_size - 1) >> log2_block_size) << log2_block_size) + + /* block num --> byte offset on disk */ +-#define boffs(block) ((block) << log2_block_size) ++#define boffs(block) ((off_t) (block) << log2_block_size) + /* byte offset on disk --> block num */ + #define boffs_block(offs) ((offs) >> log2_block_size) + ++/* pointer to in-memory block -> index in disk_cache_info */ ++#define bptr_index(ptr) (((char *)ptr - (char *)disk_cache) >> log2_block_size) ++ + /* byte offset on disk --> pointer to in-memory block */ +-#define boffs_ptr(offs) (((char *)disk_image) + (offs)) ++EXT2FS_EI char * ++boffs_ptr (off_t offset) ++{ ++ block_t block = boffs_block (offset); ++ mutex_lock (&disk_cache_lock); ++ char *ptr = hurd_ihash_find (disk_cache_bptr, block); ++ mutex_unlock (&disk_cache_lock); ++ assert (ptr); ++ ptr += offset % block_size; ++ ext2_debug ("(%Ld) = %p", offset, ptr); ++ return ptr; ++} ++ + /* pointer to in-memory block --> byte offset on disk */ +-#define bptr_offs(ptr) ((char *)(ptr) - ((char *)disk_image)) ++EXT2FS_EI off_t ++bptr_offs (void *ptr) ++{ ++ vm_offset_t mem_offset = (char *)ptr - (char *)disk_cache; ++ off_t offset; ++ assert (mem_offset < disk_cache_size); ++ mutex_lock (&disk_cache_lock); ++ offset = (off_t) disk_cache_info[boffs_block (mem_offset)].block ++ << log2_block_size; ++ assert (offset || mem_offset < block_size); ++ offset += mem_offset % block_size; ++ mutex_unlock (&disk_cache_lock); ++ ext2_debug ("(%p) = %Ld", ptr, offset); ++ return offset; ++} + + /* block num --> pointer to in-memory block */ + #define bptr(block) boffs_ptr(boffs(block)) +@@ -296,14 +377,24 @@ struct ext2_group_desc *group_desc_image + + /* Convert an inode number to the dinode on disk. */ + EXT2FS_EI struct ext2_inode * +-dino (ino_t inum) ++dino_ref (ino_t inum) + { + unsigned long inodes_per_group = sblock->s_inodes_per_group; + unsigned long bg_num = (inum - 1) / inodes_per_group; + unsigned long group_inum = (inum - 1) % inodes_per_group; +- struct ext2_group_desc *bg = group_desc(bg_num); ++ struct ext2_group_desc *bg = group_desc (bg_num); + block_t block = bg->bg_inode_table + (group_inum / inodes_per_block); +- return ((struct ext2_inode *)bptr(block)) + group_inum % inodes_per_block; ++ struct ext2_inode *inode = disk_cache_block_ref (block); ++ inode += group_inum % inodes_per_block; ++ ext2_debug ("(%qd) = %p", inum, inode); ++ return inode; ++} ++ ++EXT2FS_EI void ++dino_deref (struct ext2_inode *inode) ++{ ++ ext2_debug ("(%p)", inode); ++ disk_cache_block_deref (inode); + } + + /* ---------------------------------------------------------------- */ +@@ -356,27 +447,38 @@ global_block_modified (block_t block) + EXT2FS_EI void + record_global_poke (void *ptr) + { +- int boffs = trunc_block (bptr_offs (ptr)); +- global_block_modified (boffs_block (boffs)); +- pokel_add (&global_pokel, boffs_ptr(boffs), block_size); ++ block_t block = boffs_block (bptr_offs (ptr)); ++ void *block_ptr = bptr (block); ++ ext2_debug ("(%p = %p)", ptr, block_ptr); ++ assert (disk_cache_block_is_ref (block)); ++ global_block_modified (block); ++ pokel_add (&global_pokel, block_ptr, block_size); + } + + /* This syncs a modification to a non-file block. */ + EXT2FS_EI void + sync_global_ptr (void *bptr, int wait) + { +- vm_offset_t boffs = trunc_block (bptr_offs (bptr)); +- global_block_modified (boffs_block (boffs)); +- pager_sync_some (diskfs_disk_pager, trunc_page (boffs), vm_page_size, wait); ++ block_t block = boffs_block (bptr_offs (bptr)); ++ void *block_ptr = bptr (block); ++ ext2_debug ("(%p -> %u)", bptr, (block_t)block); ++ global_block_modified (block); ++ disk_cache_block_deref (block_ptr); ++ pager_sync_some (diskfs_disk_pager, ++ block_ptr - disk_cache, block_size, wait); ++ + } + + /* This records a modification to one of a file's indirect blocks. */ + EXT2FS_EI void + record_indir_poke (struct node *node, void *ptr) + { +- int boffs = trunc_block (bptr_offs (ptr)); +- global_block_modified (boffs_block (boffs)); +- pokel_add (&node->dn->indir_pokel, boffs_ptr(boffs), block_size); ++ block_t block = boffs_block (bptr_offs (ptr)); ++ void *block_ptr = bptr (block); ++ ext2_debug ("(%d, %p)", (int)node->cache_id, ptr); ++ assert (disk_cache_block_is_ref (block)); ++ global_block_modified (block); ++ pokel_add (&node->dn->indir_pokel, block_ptr, block_size); + } + + /* ---------------------------------------------------------------- */ +@@ -384,6 +486,7 @@ record_indir_poke (struct node *node, vo + EXT2FS_EI void + sync_global (int wait) + { ++ ext2_debug ("%d", wait); + pokel_sync (&global_pokel, wait); + } + +--- a/ext2fs/getblk.c ++++ b/ext2fs/getblk.c +@@ -52,7 +52,7 @@ ext2_discard_prealloc (struct node *node + if (node->dn->info.i_prealloc_count) + { + int i = node->dn->info.i_prealloc_count; +- ext2_debug ("discarding %d prealloced blocks for inode %d", ++ ext2_debug ("discarding %d prealloced blocks for inode %Ld", + i, node->cache_id); + node->dn->info.i_prealloc_count = 0; + ext2_free_blocks (node->dn->info.i_prealloc_block, i); +@@ -104,8 +104,8 @@ ext2_alloc_block (struct node *node, blo + + if (result && zero) + { +- char *bh = bptr (result); +- bzero (bh, block_size); ++ char *bh = disk_cache_block_ref (result); ++ memset (bh, 0, block_size); + record_indir_poke (node, bh); + } + +@@ -122,6 +122,8 @@ inode_getblk (struct node *node, int nr, + block_t hint; + #endif + ++ assert (0 <= nr && nr < EXT2_N_BLOCKS); ++ + *result = node->dn->info.i_data[nr]; + if (*result) + return 0; +@@ -180,14 +182,20 @@ block_getblk (struct node *node, block_t + { + int i; + block_t goal = 0; +- block_t *bh = (block_t *)bptr (block); ++ block_t *bh = (block_t *)disk_cache_block_ref (block); + + *result = bh[nr]; + if (*result) +- return 0; ++ { ++ disk_cache_block_deref (bh); ++ return 0; ++ } + + if (!create) +- return EINVAL; ++ { ++ disk_cache_block_deref (bh); ++ return EINVAL; ++ } + + if (node->dn->info.i_next_alloc_block == new_block) + goal = node->dn->info.i_next_alloc_goal; +@@ -207,7 +215,10 @@ block_getblk (struct node *node, block_t + + *result = ext2_alloc_block (node, goal, zero); + if (!*result) +- return ENOSPC; ++ { ++ disk_cache_block_deref (bh); ++ return ENOSPC; ++ } + + bh[nr] = *result; + +@@ -243,9 +254,9 @@ ext2_getblk (struct node *node, block_t + return EIO; + } + /* +- * If this is a sequential block allocation, set the next_alloc_block +- * to this block now so that all the indblock and data block +- * allocations use the same goal zone ++ * If this is a sequential block allocation, set the next_alloc_block ++ * to this block now so that all the indblock and data block ++ * allocations use the same goal zone + */ + + ext2_debug ("block = %u, next = %u, goal = %u", block, +--- a/ext2fs/hyper.c ++++ b/ext2fs/hyper.c +@@ -58,12 +58,15 @@ static int ext2fs_clean; /* fs clean bef + void + get_hypermetadata (void) + { +- error_t err = diskfs_catch_exception (); +- if (err) +- ext2_panic ("can't read superblock: %s", strerror (err)); +- +- sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS); ++ error_t err; ++ size_t read = 0; + ++ assert (! sblock); ++ err = store_read (store, SBLOCK_OFFS >> store->log2_block_size, ++ SBLOCK_SIZE, (void **)&sblock, &read); ++ if (err || read != SBLOCK_SIZE) ++ ext2_panic ("Cannot read hypermetadata"); ++ + if (sblock->s_magic != EXT2_SUPER_MAGIC + #ifdef EXT2FS_PRE_02B_COMPAT + && sblock->s_magic != EXT2_PRE_02B_MAGIC +@@ -152,15 +155,22 @@ get_hypermetadata (void) + + allocate_mod_map (); + +- diskfs_end_catch_exception (); ++ /* A handy source of page-aligned zeros. */ ++ if (zeroblock == 0) ++ zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0); ++ ++ munmap (sblock, SBLOCK_SIZE); ++ sblock = NULL; ++} ++ ++void ++map_hypermetadata (void) ++{ ++ sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS); + + /* Cache a convenient pointer to the block group descriptors for allocation. + These are stored in the filesystem blocks following the superblock. */ + group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (sblock) + 1); +- +- /* A handy source of page-aligned zeros. */ +- if (zeroblock == 0) +- zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0); + } + + error_t +@@ -183,6 +193,7 @@ diskfs_set_hypermetadata (int wait, int + if (sblock_dirty) + { + sblock_dirty = 0; ++ disk_cache_block_ref_ptr (sblock); + record_global_poke (sblock); + } + +@@ -199,7 +210,8 @@ diskfs_readonly_changed (int readonly) + + (*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY); + +- mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE)); ++ mprotect (disk_cache, disk_cache_size, ++ PROT_READ | (readonly ? 0 : PROT_WRITE)); + + if (!readonly && !(sblock->s_state & EXT2_VALID_FS)) + ext2_warning ("UNCLEANED FILESYSTEM NOW WRITABLE"); +--- a/ext2fs/ialloc.c ++++ b/ext2fs/ialloc.c +@@ -60,7 +60,7 @@ diskfs_free_node (struct node *np, mode_ + + assert (!diskfs_readonly); + +- ext2_debug ("freeing inode %u", inum); ++ ext2_debug ("freeing inode %Lu", inum); + + spin_lock (&global_lock); + +@@ -75,22 +75,25 @@ diskfs_free_node (struct node *np, mode_ + bit = (inum - 1) % sblock->s_inodes_per_group; + + gdp = group_desc (block_group); +- bh = bptr (gdp->bg_inode_bitmap); ++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap); + + if (!clear_bit (bit, bh)) + ext2_warning ("bit already cleared for inode %Ld", inum); + else + { ++ disk_cache_block_ref_ptr (bh); + record_global_poke (bh); + + gdp->bg_free_inodes_count++; + if (S_ISDIR (old_mode)) + gdp->bg_used_dirs_count--; ++ disk_cache_block_ref_ptr (gdp); + record_global_poke (gdp); + + sblock->s_free_inodes_count++; + } + ++ disk_cache_block_deref (bh); + sblock_dirty = 1; + spin_unlock (&global_lock); + alloc_sync(0); +@@ -111,14 +114,15 @@ diskfs_free_node (struct node *np, mode_ + ino_t + ext2_alloc_inode (ino_t dir_inum, mode_t mode) + { +- char *bh; ++ char *bh = 0; + int i, j, inum, avefreei; + struct ext2_group_desc *gdp; + struct ext2_group_desc *tmp; + + spin_lock (&global_lock); + +-repeat: ++ repeat: ++ assert (! bh); + gdp = NULL; + i = 0; + +@@ -213,7 +217,7 @@ repeat: + return 0; + } + +- bh = bptr (gdp->bg_inode_bitmap); ++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap); + if ((inum = + find_first_zero_bit ((unsigned long *) bh, sblock->s_inodes_per_group)) + < sblock->s_inodes_per_group) +@@ -221,12 +225,17 @@ repeat: + if (set_bit (inum, bh)) + { + ext2_warning ("bit already set for inode %d", inum); ++ disk_cache_block_deref (bh); ++ bh = 0; + goto repeat; + } + record_global_poke (bh); ++ bh = 0; + } + else + { ++ disk_cache_block_deref (bh); ++ bh = 0; + if (gdp->bg_free_inodes_count != 0) + { + ext2_error ("free inodes count corrupted in group %d", i); +@@ -248,15 +257,25 @@ repeat: + gdp->bg_free_inodes_count--; + if (S_ISDIR (mode)) + gdp->bg_used_dirs_count++; ++ disk_cache_block_ref_ptr (gdp); + record_global_poke (gdp); + + sblock->s_free_inodes_count--; + sblock_dirty = 1; + + sync_out: ++ assert (! bh); + spin_unlock (&global_lock); + alloc_sync (0); + ++ /* Make sure the coming read_node won't complain about bad ++ fields. */ ++ { ++ struct ext2_inode *di = dino_ref (inum); ++ memset (di, 0, sizeof *di); ++ dino_deref (di); ++ } ++ + return inum; + } + +@@ -354,10 +373,12 @@ ext2_count_free_inodes () + gdp = NULL; + for (i = 0; i < groups_count; i++) + { ++ void *bh; + gdp = group_desc (i); + desc_count += gdp->bg_free_inodes_count; +- x = count_free (bptr (gdp->bg_inode_bitmap), +- sblock->s_inodes_per_group / 8); ++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap); ++ x = count_free (bh, sblock->s_inodes_per_group / 8); ++ disk_cache_block_deref (bh); + ext2_debug ("group %d: stored = %d, counted = %lu", + i, gdp->bg_free_inodes_count, x); + bitmap_count += x; +@@ -387,10 +408,12 @@ ext2_check_inodes_bitmap () + gdp = NULL; + for (i = 0; i < groups_count; i++) + { ++ void *bh; + gdp = group_desc (i); + desc_count += gdp->bg_free_inodes_count; +- x = count_free (bptr (gdp->bg_inode_bitmap), +- sblock->s_inodes_per_group / 8); ++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap); ++ x = count_free (bh, sblock->s_inodes_per_group / 8); ++ disk_cache_block_deref (bh); + if (gdp->bg_free_inodes_count != x) + ext2_error ("wrong free inodes count in group %d, " + "stored = %d, counted = %lu", +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -92,7 +92,7 @@ diskfs_cached_lookup (ino_t inum, struct + dn->dir_idx = 0; + dn->pager = 0; + rwlock_init (&dn->alloc_lock); +- pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_image); ++ pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache); + + /* Create the new node. */ + np = diskfs_make_node (dn); +@@ -201,13 +201,17 @@ read_node (struct node *np) + error_t err; + struct stat *st = &np->dn_stat; + struct disknode *dn = np->dn; +- struct ext2_inode *di = dino (np->cache_id); ++ struct ext2_inode *di; + struct ext2_inode_info *info = &dn->info; + ++ ext2_debug ("(%d)", np->cache_id); ++ + err = diskfs_catch_exception (); + if (err) + return err; + ++ di = dino_ref (np->cache_id); ++ + st->st_fstype = FSTYPE_EXT2FS; + st->st_fsid = getpid (); /* This call is very cheap. */ + st->st_ino = np->cache_id; +@@ -285,7 +289,9 @@ read_node (struct node *np) + info->i_high_size = di->i_size_high; + if (info->i_high_size) /* XXX */ + { ++ dino_deref (di); + ext2_warning ("cannot handle large file inode %Ld", np->cache_id); ++ diskfs_end_catch_exception (); + return EFBIG; + } + } +@@ -307,20 +313,12 @@ read_node (struct node *np) + } + dn->info_i_translator = di->i_translator; + ++ dino_deref (di); + diskfs_end_catch_exception (); + + if (S_ISREG (st->st_mode) || S_ISDIR (st->st_mode) + || (S_ISLNK (st->st_mode) && st->st_blocks)) +- { +- unsigned offset; +- +- np->allocsize = np->dn_stat.st_size; +- +- /* Round up to a block multiple. */ +- offset = np->allocsize & ((1 << log2_block_size) - 1); +- if (offset > 0) +- np->allocsize += block_size - offset; +- } ++ np->allocsize = round_block (np->dn_stat.st_size); + else + /* Allocsize should be zero for anything except directories, files, and + long symlinks. These are the only things allowed to have any blocks +@@ -408,7 +406,9 @@ write_node (struct node *np) + { + error_t err; + struct stat *st = &np->dn_stat; +- struct ext2_inode *di = dino (np->cache_id); ++ struct ext2_inode *di; ++ ++ ext2_debug ("(%d)", np->cache_id); + + if (np->dn->info.i_prealloc_count) + ext2_discard_prealloc (np); +@@ -419,12 +419,14 @@ write_node (struct node *np) + + assert (!diskfs_readonly); + +- ext2_debug ("writing inode %d to disk", np->cache_id); ++ ext2_debug ("writing inode %Ld to disk", np->cache_id); + + err = diskfs_catch_exception (); + if (err) + return NULL; + ++ di = dino_ref (np->cache_id); ++ + di->i_generation = st->st_gen; + + /* We happen to know that the stat mode bits are the same +@@ -505,6 +507,7 @@ write_node (struct node *np) + diskfs_end_catch_exception (); + np->dn_stat_dirty = 0; + ++ /* Leave invoking dino_deref (di) to the caller. */ + return di; + } + else +@@ -664,7 +667,7 @@ diskfs_set_translator (struct node *np, + if (err) + return err; + +- di = dino (np->cache_id); ++ di = dino_ref (np->cache_id); + blkno = di->i_translator; + + if (namelen && !blkno) +@@ -677,6 +680,7 @@ diskfs_set_translator (struct node *np, + 0, 0, 0); + if (blkno == 0) + { ++ dino_deref (di); + diskfs_end_catch_exception (); + return ENOSPC; + } +@@ -700,15 +704,20 @@ diskfs_set_translator (struct node *np, + np->dn_stat.st_mode &= ~S_IPTRANS; + np->dn_set_ctime = 1; + } ++ else ++ dino_deref (di); + + if (namelen) + { ++ void *blkptr; ++ + buf[0] = namelen & 0xFF; + buf[1] = (namelen >> 8) & 0xFF; +- bcopy (name, buf + 2, namelen); ++ memcpy (buf + 2, name, namelen); + +- bcopy (buf, bptr (blkno), block_size); +- record_global_poke (bptr (blkno)); ++ blkptr = disk_cache_block_ref (blkno); ++ memcpy (blkptr, buf, block_size); ++ record_global_poke (blkptr); + + np->dn_stat.st_mode |= S_IPTRANS; + np->dn_set_ctime = 1; +@@ -726,7 +735,7 @@ diskfs_get_translator (struct node *np, + error_t err = 0; + daddr_t blkno; + unsigned datalen; +- const void *transloc; ++ void *transloc; + + assert (sblock->s_creator_os == EXT2_OS_HURD); + +@@ -734,9 +743,11 @@ diskfs_get_translator (struct node *np, + if (err) + return err; + +- blkno = (dino (np->cache_id))->i_translator; ++ struct ext2_inode *di = dino_ref (np->cache_id); ++ blkno = di->i_translator; ++ dino_deref (di); + assert (blkno); +- transloc = bptr (blkno); ++ transloc = disk_cache_block_ref (blkno); + + datalen = + ((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8); +@@ -751,6 +762,7 @@ diskfs_get_translator (struct node *np, + memcpy (*namep, transloc + 2, datalen); + } + ++ disk_cache_block_deref (transloc); + diskfs_end_catch_exception (); + + *namelen = datalen; +@@ -772,7 +784,7 @@ write_symlink (struct node *node, const + + assert (node->dn_stat.st_blocks == 0); + +- bcopy (target, node->dn->info.i_data, len); ++ memcpy (node->dn->info.i_data, target, len); + node->dn_stat.st_size = len - 1; + node->dn_set_ctime = 1; + node->dn_set_mtime = 1; +@@ -789,7 +801,7 @@ read_symlink (struct node *node, char *t + + assert (node->dn_stat.st_size < MAX_INODE_SYMLINK); + +- bcopy (node->dn->info.i_data, target, node->dn_stat.st_size); ++ memcpy (target, node->dn->info.i_data, node->dn_stat.st_size); + return 0; + } + +--- a/ext2fs/pager.c ++++ b/ext2fs/pager.c +@@ -18,17 +18,18 @@ + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + ++#include <unistd.h> + #include <string.h> + #include <errno.h> + #include <hurd/store.h> + #include "ext2fs.h" + ++/* XXX */ ++#include "../libpager/priv.h" ++ + /* A ports bucket to hold pager ports. */ + struct port_bucket *pager_bucket; + +-/* Mapped image of the disk. */ +-void *disk_image; +- + spin_lock_t node_to_page_lock = SPIN_LOCK_INITIALIZER; + + #ifdef DONT_CACHE_MEMORY_OBJECTS +@@ -163,6 +164,9 @@ file_pager_read_page (struct node *node, + block_t pending_blocks = 0; + int num_pending_blocks = 0; + ++ ext2_debug ("reading inode %Ld page %u[%d]", ++ node->cache_id, page, vm_page_size); ++ + /* Read the NUM_PENDING_BLOCKS blocks in PENDING_BLOCKS, into the buffer + pointed to by BUF (allocating it if necessary) at offset OFFS. OFFS in + adjusted by the amount read, and NUM_PENDING_BLOCKS is zeroed. Any read +@@ -171,7 +175,8 @@ file_pager_read_page (struct node *node, + { + if (num_pending_blocks > 0) + { +- block_t dev_block = pending_blocks << log2_dev_blocks_per_fs_block; ++ store_offset_t dev_block = (store_offset_t) pending_blocks ++ << log2_dev_blocks_per_fs_block; + size_t amount = num_pending_blocks << log2_block_size; + /* The buffer we try to read into; on the first read, we pass in a + size of zero, so that the read is guaranteed to allocate a new +@@ -198,7 +203,7 @@ file_pager_read_page (struct node *node, + else + /* We've already got some buffer, so copy into it. */ + { +- bcopy (new_buf, *buf + offs, new_len); ++ memcpy (*buf + offs, new_buf, new_len); + free_page_buf (new_buf); /* Return NEW_BUF to our pool. */ + STAT_INC (file_pagein_freed_bufs); + } +@@ -254,7 +259,7 @@ file_pager_read_page (struct node *node, + break; + STAT_INC (file_pagein_alloced_bufs); + } +- bzero (*buf + offs, block_size); ++ memset (*buf + offs, 0, block_size); + offs += block_size; + } + else +@@ -295,16 +300,17 @@ pending_blocks_write (struct pending_blo + if (pb->num > 0) + { + error_t err; +- block_t dev_block = pb->block << log2_dev_blocks_per_fs_block; ++ store_offset_t dev_block = (store_offset_t) pb->block ++ << log2_dev_blocks_per_fs_block; + size_t length = pb->num << log2_block_size, amount; + +- ext2_debug ("writing block %u[%ld]", pb->block, pb->num); ++ ext2_debug ("writing block %u[%Ld]", pb->block, pb->num); + + if (pb->offs > 0) + /* Put what we're going to write into a page-aligned buffer. */ + { + void *page_buf = get_page_buf (); +- bcopy (pb->buf + pb->offs, (void *)page_buf, length); ++ memcpy ((void *)page_buf, pb->buf + pb->offs, length); + err = store_write (store, dev_block, page_buf, length, &amount); + free_page_buf (page_buf); + } +@@ -357,7 +363,7 @@ pending_blocks_add (struct pending_block + return 0; + } + +-/* Write one page for the pager backing NODE, at offset PAGE, into BUF. This ++/* Write one page for the pager backing NODE, at OFFSET, into BUF. This + may need to write several filesystem blocks to satisfy one page, and tries + to consolidate the i/o if possible. */ + static error_t +@@ -381,7 +387,7 @@ file_pager_write_page (struct node *node + else if (offset + left > node->allocsize) + left = node->allocsize - offset; + +- ext2_debug ("writing inode %d page %d[%d]", node->cache_id, offset, left); ++ ext2_debug ("writing inode %Ld page %u[%d]", node->cache_id, offset, left); + + STAT_INC (file_pageouts); + +@@ -409,16 +415,31 @@ disk_pager_read_page (vm_offset_t page, + { + error_t err; + size_t length = vm_page_size, read = 0; +- vm_size_t dev_end = store->size; ++ store_offset_t offset = page, dev_end = store->size; + +- if (page + vm_page_size > dev_end) +- length = dev_end - page; ++ mutex_lock (&disk_cache_lock); ++ int index = offset >> log2_block_size; ++ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size) ++ + offset % block_size; ++ disk_cache_info[index].flags |= DC_INCORE; ++ disk_cache_info[index].flags &=~ DC_UNTOUCHED; ++#ifndef NDEBUG ++ disk_cache_info[index].last_read = disk_cache_info[index].block; ++ disk_cache_info[index].last_read_xor ++ = disk_cache_info[index].block ^ DISK_CACHE_LAST_READ_XOR; ++#endif ++ ext2_debug ("(%Ld)", offset >> log2_block_size); ++ mutex_unlock (&disk_cache_lock); ++ ++ if (offset + vm_page_size > dev_end) ++ length = dev_end - offset; + +- err = store_read (store, page >> store->log2_block_size, length, buf, &read); ++ err = store_read (store, offset >> store->log2_block_size, length, ++ buf, &read); + if (read != length) + return EIO; + if (!err && length != vm_page_size) +- bzero ((void *)(*buf + length), vm_page_size - length); ++ memset ((void *)(*buf + length), 0, vm_page_size - length); + + *writelock = 0; + +@@ -430,26 +451,38 @@ disk_pager_write_page (vm_offset_t page, + { + error_t err = 0; + size_t length = vm_page_size, amount; +- vm_size_t dev_end = store->size; ++ store_offset_t offset = page, dev_end = store->size; ++ ++ mutex_lock (&disk_cache_lock); ++ int index = offset >> log2_block_size; ++ assert (disk_cache_info[index].block != DC_NO_BLOCK); ++ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size) ++ + offset % block_size; ++#ifndef NDEBUG /* Not strictly needed. */ ++ assert ((disk_cache_info[index].last_read ^ DISK_CACHE_LAST_READ_XOR) ++ == disk_cache_info[index].last_read_xor); ++ assert (disk_cache_info[index].last_read ++ == disk_cache_info[index].block); ++#endif ++ mutex_unlock (&disk_cache_lock); + +- if (page + vm_page_size > dev_end) +- length = dev_end - page; ++ if (offset + vm_page_size > dev_end) ++ length = dev_end - offset; + +- ext2_debug ("writing disk page %d[%d]", page, length); ++ ext2_debug ("writing disk page %Ld[%d]", offset, length); + + STAT_INC (disk_pageouts); + + if (modified_global_blocks) + /* Be picky about which blocks in a page that we write. */ + { +- vm_offset_t offs = page; + struct pending_blocks pb; + + pending_blocks_init (&pb, buf); + + while (length > 0 && !err) + { +- block_t block = boffs_block (offs); ++ block_t block = boffs_block (offset); + + /* We don't clear the block modified bit here because this paging + write request may not be the same one that actually set the bit, +@@ -467,7 +500,7 @@ disk_pager_write_page (vm_offset_t page, + /* Otherwise just skip it. */ + err = pending_blocks_skip (&pb); + +- offs += block_size; ++ offset += block_size; + length -= block_size; + } + +@@ -476,7 +509,7 @@ disk_pager_write_page (vm_offset_t page, + } + else + { +- err = store_write (store, page >> store->log2_block_size, ++ err = store_write (store, offset >> store->log2_block_size, + buf, length, &amount); + if (!err && length != amount) + err = EIO; +@@ -484,6 +517,18 @@ disk_pager_write_page (vm_offset_t page, + + return err; + } ++ ++static void ++disk_pager_notify_evict (vm_offset_t page) ++{ ++ int index = page >> log2_block_size; ++ ++ ext2_debug ("(block %u)", index); ++ ++ mutex_lock (&disk_cache_lock); ++ disk_cache_info[index].flags &= ~DC_INCORE; ++ mutex_unlock (&disk_cache_lock); ++} + + /* Satisfy a pager read request for either the disk pager or file pager + PAGER, to the page at offset PAGE into BUF. WRITELOCK should be set if +@@ -493,9 +538,11 @@ pager_read_page (struct user_pager_info + vm_address_t *buf, int *writelock) + { + if (pager->type == DISK) +- return disk_pager_read_page (page, (void **)buf, writelock); ++ return disk_pager_read_page (page, (void **)buf, ++ writelock); + else +- return file_pager_read_page (pager->node, page, (void **)buf, writelock); ++ return file_pager_read_page (pager->node, page, (void **)buf, ++ writelock); + } + + /* Satisfy a pager write request for either the disk pager or file pager +@@ -509,6 +556,14 @@ pager_write_page (struct user_pager_info + else + return file_pager_write_page (pager->node, page, (void *)buf); + } ++ ++void ++pager_notify_evict (struct user_pager_info *pager, vm_offset_t page) ++{ ++ if (pager->type == DISK) ++ disk_pager_notify_evict (page); ++} ++ + + /* Make page PAGE writable, at least up to ALLOCSIZE. This function and + diskfs_grow are the only places that blocks are actually added to the +@@ -558,10 +613,10 @@ pager_unlock_page (struct user_pager_inf + + #ifdef EXT2FS_DEBUG + if (dn->last_page_partially_writable) +- ext2_debug ("made page %u[%lu] in inode %d partially writable", ++ ext2_debug ("made page %u[%Lu] in inode %Ld partially writable", + page, node->allocsize - page, node->cache_id); + else +- ext2_debug ("made page %u[%u] in inode %d writable", ++ ext2_debug ("made page %u[%u] in inode %Ld writable", + page, vm_page_size, node->cache_id); + #endif + +@@ -619,8 +674,8 @@ diskfs_grow (struct node *node, off_t si + block_t old_page_end_block = + round_page (old_size) >> log2_block_size; + +- ext2_debug ("growing inode %d to %lu bytes (from %lu)", node->cache_id, +- new_size, old_size); ++ ext2_debug ("growing inode %Ld to %Lu bytes (from %Lu)", ++ node->cache_id, new_size, old_size); + + if (dn->last_page_partially_writable + && old_page_end_block > end_block) +@@ -656,11 +711,11 @@ diskfs_grow (struct node *node, off_t si + + STAT_INC (file_grows); + +- ext2_debug ("new size: %ld%s.", new_size, ++ ext2_debug ("new size: %Lu%s.", new_size, + dn->last_page_partially_writable + ? " (last page writable)": ""); + if (err) +- ext2_warning ("inode=%Ld, target=%Ld: %s", ++ ext2_warning ("inode=%Ld, target=%Lu: %s", + node->cache_id, new_size, strerror (err)); + + node->allocsize = new_size; +@@ -765,6 +820,374 @@ pager_dropweak (struct user_pager_info * + { + } + ++/* Cached blocks from disk. */ ++void *disk_cache; ++ ++/* DISK_CACHE size in bytes and blocks. */ ++store_offset_t disk_cache_size; ++int disk_cache_blocks; ++ ++/* block num --> pointer to in-memory block */ ++hurd_ihash_t disk_cache_bptr; ++/* Cached blocks' info. */ ++struct disk_cache_info *disk_cache_info; ++/* Hint index for which cache block to reuse next. */ ++int disk_cache_hint; ++/* Lock for these structures. */ ++struct mutex disk_cache_lock; ++/* Fired when a re-association is done. */ ++struct condition disk_cache_reassociation; ++ ++/* Finish mapping initialization. */ ++static void ++disk_cache_init (void) ++{ ++ if (block_size != vm_page_size) ++ ext2_panic ("Block size %d != vm_page_size %d", ++ block_size, vm_page_size); ++ ++ mutex_init (&disk_cache_lock); ++ condition_init (&disk_cache_reassociation); ++ ++ /* Allocate space for block num -> in-memory pointer mapping. */ ++ if (hurd_ihash_create (&disk_cache_bptr, HURD_IHASH_NO_LOCP)) ++ ext2_panic ("Can't allocate memory for disk_pager_bptr"); ++ ++ /* Allocate space for disk cache blocks' info. */ ++ disk_cache_info = malloc ((sizeof *disk_cache_info) * disk_cache_blocks); ++ if (!disk_cache_info) ++ ext2_panic ("Cannot allocate space for disk cache info"); ++ ++ /* Initialize disk_cache_info. */ ++ for (int i = 0; i < disk_cache_blocks; i++) ++ { ++ disk_cache_info[i].block = DC_NO_BLOCK; ++ disk_cache_info[i].flags = 0; ++ disk_cache_info[i].ref_count = 0; ++#ifndef NDEBUG ++ disk_cache_info[i].last_read = DC_NO_BLOCK; ++ disk_cache_info[i].last_read_xor ++ = DC_NO_BLOCK ^ DISK_CACHE_LAST_READ_XOR; ++#endif ++ } ++ disk_cache_hint = 0; ++ ++ /* Map the superblock and the block group descriptors. */ ++ block_t fixed_first = boffs_block (SBLOCK_OFFS); ++ block_t fixed_last = fixed_first ++ + (round_block ((sizeof *group_desc_image) * groups_count) ++ >> log2_block_size); ++ ext2_debug ("%d-%d\n", fixed_first, fixed_last); ++ assert (fixed_last - fixed_first + 1 <= (block_t)disk_cache_blocks + 3); ++ for (block_t i = fixed_first; i <= fixed_last; i++) ++ { ++ disk_cache_block_ref (i); ++ assert (disk_cache_info[i-fixed_first].block == i); ++ disk_cache_info[i-fixed_first].flags |= DC_FIXED; ++ } ++} ++ ++static void ++disk_cache_return_unused (void) ++{ ++ int index; ++ ++ /* XXX: Touch all pages. It seems that sometimes GNU Mach "forgets" ++ to notify us about evicted pages. Disk cache must be ++ unlocked. */ ++ for (vm_offset_t i = 0; i < disk_cache_size; i += vm_page_size) ++ *(volatile char *)(disk_cache + i); ++ ++ /* Release some references to cached blocks. */ ++ pokel_sync (&global_pokel, 1); ++ ++ /* Return unused pages that are in core. */ ++ int pending_begin = -1, pending_end = -1; ++ mutex_lock (&disk_cache_lock); ++ for (index = 0; index < disk_cache_blocks; index++) ++ if (! (disk_cache_info[index].flags & (DC_DONT_REUSE & ~DC_INCORE)) ++ && ! disk_cache_info[index].ref_count) ++ { ++ ext2_debug ("return %u -> %d", ++ disk_cache_info[index].block, index); ++ if (index != pending_end) ++ { ++ /* Return previous region, if there is such, ... */ ++ if (pending_end >= 0) ++ { ++ mutex_unlock (&disk_cache_lock); ++ pager_return_some (diskfs_disk_pager, ++ pending_begin * vm_page_size, ++ (pending_end - pending_begin) ++ * vm_page_size, ++ 1); ++ mutex_lock (&disk_cache_lock); ++ } ++ /* ... and start new region. */ ++ pending_begin = index; ++ } ++ pending_end = index + 1; ++ } ++ ++ mutex_unlock (&disk_cache_lock); ++ ++ /* Return last region, if there is such. */ ++ if (pending_end >= 0) ++ pager_return_some (diskfs_disk_pager, ++ pending_begin * vm_page_size, ++ (pending_end - pending_begin) * vm_page_size, ++ 1); ++ else ++ { ++ printf ("ext2fs: disk cache is starving\n"); ++ ++ /* Give it some time. This should happen rarely. */ ++ sleep (1); ++ } ++} ++ ++/* Map block and return pointer to it. */ ++void * ++disk_cache_block_ref (block_t block) ++{ ++ int index; ++ void *bptr; ++ ++ assert (0 <= block && block < store->size >> log2_block_size); ++ ++ ext2_debug ("(%u)", block); ++ ++ mutex_lock (&disk_cache_lock); ++ ++ bptr = hurd_ihash_find (disk_cache_bptr, block); ++ if (bptr) ++ /* Already mapped. */ ++ { ++ index = bptr_index (bptr); ++ ++ /* In process of re-associating? */ ++ if (disk_cache_info[index].flags & DC_UNTOUCHED) ++ { ++ /* Wait re-association to finish. */ ++ condition_wait (&disk_cache_reassociation, &disk_cache_lock); ++ mutex_unlock (&disk_cache_lock); ++ ++#if 0 ++ printf ("Re-association -- wait finished.\n"); ++#endif ++ ++ /* Try again. */ ++ return disk_cache_block_ref (block); /* tail recursion */ ++ } ++ ++ /* Just increment reference and return. */ ++ assert (disk_cache_info[index].ref_count + 1 ++ > disk_cache_info[index].ref_count); ++ disk_cache_info[index].ref_count++; ++ ++ ext2_debug ("cached %u -> %d (ref_count = %d, flags = 0x%x, ptr = %p)", ++ disk_cache_info[index].block, index, ++ disk_cache_info[index].ref_count, ++ disk_cache_info[index].flags, bptr); ++ ++ mutex_unlock (&disk_cache_lock); ++ ++ return bptr; ++ } ++ ++ /* Search for a block that is not in core and is not referenced. */ ++ index = disk_cache_hint; ++ while ((disk_cache_info[index].flags & DC_DONT_REUSE) ++ || (disk_cache_info[index].ref_count)) ++ { ++ ext2_debug ("reject %u -> %d (ref_count = %d, flags = 0x%x)", ++ disk_cache_info[index].block, index, ++ disk_cache_info[index].ref_count, ++ disk_cache_info[index].flags); ++ ++ /* Just move to next block. */ ++ index++; ++ if (index >= disk_cache_blocks) ++ index -= disk_cache_blocks; ++ ++ /* If we return to where we started, than there is no suitable ++ block. */ ++ if (index == disk_cache_hint) ++ break; ++ } ++ ++ /* The next place in the disk cache becomes the current hint. */ ++ disk_cache_hint = index + 1; ++ if (disk_cache_hint >= disk_cache_blocks) ++ disk_cache_hint -= disk_cache_blocks; ++ ++ /* Is suitable place found? */ ++ if ((disk_cache_info[index].flags & DC_DONT_REUSE) ++ || disk_cache_info[index].ref_count) ++ /* No place is found. Try to release some blocks and try ++ again. */ ++ { ++ ext2_debug ("flush %u -> %d", disk_cache_info[index].block, index); ++ ++ mutex_unlock (&disk_cache_lock); ++ ++ disk_cache_return_unused (); ++ ++ return disk_cache_block_ref (block); /* tail recursion */ ++ } ++ ++ /* Suitable place is found. */ ++ ++ /* Calculate pointer to data. */ ++ bptr = (char *)disk_cache + (index << log2_block_size); ++ ext2_debug ("map %u -> %d (%p)", block, index, bptr); ++ ++ /* This pager_return_some is used only to set PM_FORCEREAD for the ++ page. DC_UNTOUCHED is set so that we catch if someone has ++ referenced the block while we didn't hold disk_cache_lock. */ ++ disk_cache_info[index].flags |= DC_UNTOUCHED; ++ ++#if 0 /* XXX: Let's see if this is needed at all. */ ++ ++ mutex_unlock (&disk_cache_lock); ++ pager_return_some (diskfs_disk_pager, bptr - disk_cache, vm_page_size, 1); ++ mutex_lock (&disk_cache_lock); ++ ++ /* Has someone used our bptr? Has someone mapped requested block ++ while we have unlocked disk_cache_lock? If so, environment has ++ changed and we have to restart operation. */ ++ if ((! (disk_cache_info[index].flags & DC_UNTOUCHED)) ++ || hurd_ihash_find (disk_cache_bptr, block)) ++ { ++ mutex_unlock (&disk_cache_lock); ++ return disk_cache_block_ref (block); /* tail recursion */ ++ } ++ ++#elif 0 ++ ++ /* XXX: Use libpager internals. */ ++ ++ mutex_lock (&diskfs_disk_pager->interlock); ++ int page = (bptr - disk_cache) / vm_page_size; ++ assert (page >= 0); ++ int is_incore = (page < diskfs_disk_pager->pagemapsize ++ && (diskfs_disk_pager->pagemap[page] & PM_INCORE)); ++ mutex_unlock (&diskfs_disk_pager->interlock); ++ if (is_incore) ++ { ++ mutex_unlock (&disk_cache_lock); ++ printf ("INCORE\n"); ++ return disk_cache_block_ref (block); /* tail recursion */ ++ } ++ ++#endif ++ ++ /* Re-associate. */ ++ if (disk_cache_info[index].block != DC_NO_BLOCK) ++ /* Remove old association. */ ++ hurd_ihash_remove (disk_cache_bptr, disk_cache_info[index].block); ++ /* New association. */ ++ if (hurd_ihash_add (disk_cache_bptr, block, bptr)) ++ ext2_panic ("Couldn't hurd_ihash_add new disk block"); ++ assert (! (disk_cache_info[index].flags & DC_DONT_REUSE & ~DC_UNTOUCHED)); ++ disk_cache_info[index].block = block; ++ assert (! disk_cache_info[index].ref_count); ++ disk_cache_info[index].ref_count = 1; ++ ++ /* All data structures are set up. */ ++ mutex_unlock (&disk_cache_lock); ++ ++ /* Try to read page. */ ++ *(volatile char *) bptr; ++ ++ /* Check if it's actually read. */ ++ mutex_lock (&disk_cache_lock); ++ if (disk_cache_info[index].flags & DC_UNTOUCHED) ++ /* It's not read. */ ++ { ++ /* Remove newly created association. */ ++ hurd_ihash_remove (disk_cache_bptr, block); ++ disk_cache_info[index].block = DC_NO_BLOCK; ++ disk_cache_info[index].flags &=~ DC_UNTOUCHED; ++ disk_cache_info[index].ref_count = 0; ++ mutex_unlock (&disk_cache_lock); ++ ++ /* Prepare next time association of this page to succeed. */ ++ pager_flush_some (diskfs_disk_pager, bptr - disk_cache, ++ vm_page_size, 0); ++ ++#if 0 ++ printf ("Re-association failed.\n"); ++#endif ++ ++ /* Try again. */ ++ return disk_cache_block_ref (block); /* tail recursion */ ++ } ++ mutex_unlock (&disk_cache_lock); ++ ++ /* Re-association was successful. */ ++ condition_broadcast (&disk_cache_reassociation); ++ ++ ext2_debug ("(%u) = %p", block, bptr); ++ return bptr; ++} ++ ++void ++disk_cache_block_ref_ptr (void *ptr) ++{ ++ int index; ++ ++ mutex_lock (&disk_cache_lock); ++ index = bptr_index (ptr); ++ assert (disk_cache_info[index].ref_count >= 1); ++ assert (disk_cache_info[index].ref_count + 1 ++ > disk_cache_info[index].ref_count); ++ disk_cache_info[index].ref_count++; ++ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED)); ++ ext2_debug ("(%p) (ref_count = %d, flags = 0x%x)", ++ ptr, ++ disk_cache_info[index].ref_count, ++ disk_cache_info[index].flags); ++ mutex_unlock (&disk_cache_lock); ++} ++ ++void ++disk_cache_block_deref (void *ptr) ++{ ++ int index; ++ ++ assert (disk_cache <= ptr && ptr <= disk_cache + disk_cache_size); ++ ++ mutex_lock (&disk_cache_lock); ++ index = bptr_index (ptr); ++ ext2_debug ("(%p) (ref_count = %d, flags = 0x%x)", ++ ptr, ++ disk_cache_info[index].ref_count - 1, ++ disk_cache_info[index].flags); ++ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED)); ++ assert (disk_cache_info[index].ref_count >= 1); ++ disk_cache_info[index].ref_count--; ++ mutex_unlock (&disk_cache_lock); ++} ++ ++/* Not used. */ ++int ++disk_cache_block_is_ref (block_t block) ++{ ++ int ref; ++ void *ptr; ++ ++ mutex_lock (&disk_cache_lock); ++ ptr = hurd_ihash_find (disk_cache_bptr, block); ++ if (! ptr) ++ ref = 0; ++ else /* XXX: Should check for DC_UNTOUCHED too. */ ++ ref = disk_cache_info[bptr_index (ptr)].ref_count; ++ mutex_unlock (&disk_cache_lock); ++ ++ return ref; ++} ++ + /* Create the DISK pager. */ + void + create_disk_pager (void) +@@ -774,8 +1197,12 @@ create_disk_pager (void) + ext2_panic ("can't create disk pager: %s", strerror (errno)); + upi->type = DISK; + pager_bucket = ports_create_bucket (); +- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size, +- &disk_image); ++ get_hypermetadata (); ++ disk_cache_blocks = DISK_CACHE_BLOCKS; ++ disk_cache_size = disk_cache_blocks << log2_block_size; ++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 1, ++ disk_cache_size, &disk_cache); ++ disk_cache_init (); + } + + /* Call this to create a FILE_DATA pager and return a send right. +@@ -815,7 +1242,7 @@ diskfs_get_filemap (struct node *node, v + diskfs_nref_light (node); + node->dn->pager = + pager_create (upi, pager_bucket, MAY_CACHE, +- MEMORY_OBJECT_COPY_DELAY); ++ MEMORY_OBJECT_COPY_DELAY, 0); + if (node->dn->pager == 0) + { + diskfs_nrele_light (node); +--- a/ext2fs/pokel.c ++++ b/ext2fs/pokel.c +@@ -67,12 +67,27 @@ pokel_add (struct pokel *pokel, void *lo + vm_offset_t p_offs = pl->offset; + vm_size_t p_end = p_offs + pl->length; + +- if (p_offs == offset && p_end == end) +- break; ++ if (p_offs <= offset && end <= p_end) ++ { ++ if (pokel->image == disk_cache) ++ for (vm_offset_t i = offset; i < end; i += block_size) ++ disk_cache_block_deref (disk_cache + i); ++ ++ break; ++ } + else if (p_end >= offset && end >= p_offs) + { + pl->offset = offset < p_offs ? offset : p_offs; + pl->length = (end > p_end ? end : p_end) - pl->offset; ++ ++ if (pokel->image == disk_cache) ++ { ++ vm_offset_t i_begin = p_offs > offset ? p_offs : offset; ++ vm_offset_t i_end = p_end < end ? p_end : end; ++ for (vm_offset_t i = i_begin; i < i_end; i += block_size) ++ disk_cache_block_deref (disk_cache + i); ++ } ++ + ext2_debug ("extended 0x%x[%ul] to 0x%x[%ul]", + p_offs, p_end - p_offs, pl->offset, pl->length); + break; +@@ -106,18 +121,28 @@ void + _pokel_exec (struct pokel *pokel, int sync, int wait) + { + struct poke *pl, *pokes, *last = NULL; +- ++ + spin_lock (&pokel->lock); + pokes = pokel->pokes; + pokel->pokes = NULL; + spin_unlock (&pokel->lock); + + for (pl = pokes; pl; last = pl, pl = pl->next) +- if (sync) +- { +- ext2_debug ("syncing 0x%x[%ul]", pl->offset, pl->length); +- pager_sync_some (pokel->pager, pl->offset, pl->length, wait); +- } ++ { ++ if (sync) ++ { ++ ext2_debug ("syncing 0x%x[%ul]", pl->offset, pl->length); ++ pager_sync_some (pokel->pager, pl->offset, pl->length, wait); ++ } ++ ++ if (pokel->image == disk_cache) ++ { ++ vm_offset_t begin = trunc_block (pl->offset); ++ vm_offset_t end = round_block (pl->offset + pl->length); ++ for (vm_offset_t i = begin; i != end; i += block_size) ++ disk_cache_block_deref (pokel->image + i); ++ } ++ } + + if (last) + { +--- a/ext2fs/truncate.c ++++ b/ext2fs/truncate.c +@@ -124,7 +124,7 @@ trunc_indirect (struct node *node, block + { + unsigned index; + int modified = 0, all_freed = 1; +- block_t *ind_bh = (block_t *)bptr (*p); ++ block_t *ind_bh = (block_t *)disk_cache_block_ref (*p); + unsigned first = end < offset ? 0 : end - offset; + + for (index = first; index < addr_per_block; index++) +@@ -139,11 +139,16 @@ trunc_indirect (struct node *node, block + + if (first == 0 && all_freed) + { +- pager_flush_some (diskfs_disk_pager, boffs (*p), block_size, 1); ++ pager_flush_some (diskfs_disk_pager, ++ bptr_index (ind_bh) << log2_block_size, ++ block_size, 1); + free_block_run_free_ptr (fbr, p); ++ disk_cache_block_deref (ind_bh); + } + else if (modified) + record_indir_poke (node, ind_bh); ++ else ++ disk_cache_block_deref (ind_bh); + } + } + +@@ -218,7 +223,7 @@ poke_pages (memory_object_t obj, vm_offs + /* Flush all the data past the new size from the kernel. Also force any + delayed copies of this data to take place immediately. (We are implicitly + changing the data to zeros and doing it without the kernel's immediate +- knowledge; accordingl we must help out the kernel thusly.) */ ++ knowledge; accordingly we must help out the kernel thusly.) */ + static void + force_delayed_copies (struct node *node, off_t length) + { +--- a/fatfs/pager.c ++++ b/fatfs/pager.c +@@ -596,6 +596,13 @@ pager_unlock_page (struct user_pager_inf + return 0; + } + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ assert (!"unrequested notification on eviction"); ++} ++ + /* Grow the disk allocated to locked node NODE to be at least SIZE + bytes, and set NODE->allocsize to the actual allocated size. (If + the allocated size is already SIZE bytes, do nothing.) CRED +@@ -752,7 +759,7 @@ create_fat_pager (void) + struct user_pager_info *upi = malloc (sizeof (struct user_pager_info)); + upi->type = FAT; + pager_bucket = ports_create_bucket (); +- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, ++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0, + bytes_per_sector * sectors_per_fat, + &fat_image); + } +@@ -794,7 +801,7 @@ diskfs_get_filemap (struct node *node, v + diskfs_nref_light (node); + node->dn->pager = + pager_create (upi, pager_bucket, MAY_CACHE, +- MEMORY_OBJECT_COPY_DELAY); ++ MEMORY_OBJECT_COPY_DELAY, 0); + if (node->dn->pager == 0) + { + diskfs_nrele_light (node); +--- a/isofs/pager.c ++++ b/isofs/pager.c +@@ -94,6 +94,13 @@ pager_unlock_page (struct user_pager_inf + return EROFS; + } + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ assert (!"unrequested notification on eviction"); ++} ++ + /* Tell how big the file is. */ + error_t + pager_report_extent (struct user_pager_info *pager, +@@ -137,7 +144,7 @@ create_disk_pager (void) + upi->type = DISK; + upi->np = 0; + pager_bucket = ports_create_bucket (); +- diskfs_start_disk_pager (upi, pager_bucket, 1, store->size, &disk_image); ++ diskfs_start_disk_pager (upi, pager_bucket, 1, 0, store->size, &disk_image); + upi->p = diskfs_disk_pager; + } + +@@ -168,7 +175,8 @@ diskfs_get_filemap (struct node *np, vm_ + upi->type = FILE_DATA; + upi->np = np; + diskfs_nref_light (np); +- upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_DELAY); ++ upi->p = pager_create (upi, pager_bucket, 1, ++ MEMORY_OBJECT_COPY_DELAY, 0); + if (upi->p == 0) + { + diskfs_nrele_light (np); +--- a/libdiskfs/disk-pager.c ++++ b/libdiskfs/disk-pager.c +@@ -46,7 +46,8 @@ service_paging_requests (any_t arg) + + void + diskfs_start_disk_pager (struct user_pager_info *upi, +- struct port_bucket *pager_bucket, int may_cache, ++ struct port_bucket *pager_bucket, ++ int may_cache, int notify_on_evict, + size_t size, void **image) + { + error_t err; +@@ -58,7 +59,8 @@ diskfs_start_disk_pager (struct user_pag + + /* Create the pager. */ + diskfs_disk_pager = pager_create (upi, pager_bucket, +- may_cache, MEMORY_OBJECT_COPY_NONE); ++ may_cache, MEMORY_OBJECT_COPY_NONE, ++ notify_on_evict); + assert (diskfs_disk_pager); + + /* Get a port to the disk pager. */ +--- a/libdiskfs/diskfs-pager.h ++++ b/libdiskfs/diskfs-pager.h +@@ -33,7 +33,8 @@ + mapped is returned in IMAGE. INFO, PAGER_BUCKET, & MAY_CACHE are passed + to `pager_create'. */ + extern void diskfs_start_disk_pager (struct user_pager_info *info, +- struct port_bucket *pager_bucket, int may_cache, ++ struct port_bucket *pager_bucket, ++ int may_cache, int notify_on_evict, + size_t size, void **image); + + extern struct pager *diskfs_disk_pager; +--- a/libpager/data-request.c ++++ b/libpager/data-request.c +@@ -40,11 +40,11 @@ _pager_seqnos_memory_object_data_request + if (!p) + return EOPNOTSUPP; + +- /* Acquire the right to meddle with the pagemap */ ++ /* Acquire the right to meddle with the pagemap. */ + mutex_lock (&p->interlock); + _pager_wait_for_seqno (p, seqno); + +- /* sanity checks -- we don't do multi-page requests yet. */ ++ /* Sanity checks -- we don't do multi-page requests yet. */ + if (control != p->memobjcntl) + { + printf ("incg data request: wrong control port\n"); +@@ -67,14 +67,16 @@ _pager_seqnos_memory_object_data_request + if (p->pager_state != NORMAL) + { + printf ("pager in wrong state for read\n"); +- _pager_release_seqno (p, seqno); +- mutex_unlock (&p->interlock); +- goto allow_term_out; ++ _pager_allow_termination (p); ++ goto release_out; + } + + err = _pager_pagemap_resize (p, offset + length); + if (err) +- goto release_out; /* Can't do much about the actual error. */ ++ { ++ _pager_allow_termination (p); ++ goto release_out; /* Can't do much about the actual error. */ ++ } + + /* If someone is paging this out right now, the disk contents are + unreliable, so we have to wait. It is too expensive (right now) to +@@ -121,7 +123,8 @@ _pager_seqnos_memory_object_data_request + goto error_read; + + memory_object_data_supply (p->memobjcntl, offset, page, length, 1, +- write_lock ? VM_PROT_WRITE : VM_PROT_NONE, 0, ++ write_lock ? VM_PROT_WRITE : VM_PROT_NONE, ++ p->notify_on_evict ? 1 : 0, + MACH_PORT_NULL); + mutex_lock (&p->interlock); + _pager_mark_object_error (p, offset, length, 0); +--- a/libpager/data-return.c ++++ b/libpager/data-return.c +@@ -39,6 +39,7 @@ _pager_do_write_request (mach_port_t obj + struct pager *p; + short *pm_entries; + int npages, i; ++ char *notified; + error_t *pagerrs; + struct lock_request *lr; + struct lock_list {struct lock_request *lr; +@@ -71,9 +72,6 @@ _pager_do_write_request (mach_port_t obj + goto release_out; + } + +- if (! dirty) +- goto release_out; +- + if (p->pager_state != NORMAL) + { + printf ("pager in wrong state for write\n"); +@@ -83,6 +81,11 @@ _pager_do_write_request (mach_port_t obj + npages = length / __vm_page_size; + pagerrs = alloca (npages * sizeof (error_t)); + ++ notified = alloca (npages * (sizeof *notified)); ++#ifndef NDEBUG ++ memset (notified, -1, npages * (sizeof *notified)); ++#endif ++ + _pager_block_termination (p); /* until we are done with the pagemap + when the write completes. */ + +@@ -90,6 +93,23 @@ _pager_do_write_request (mach_port_t obj + + pm_entries = &p->pagemap[offset / __vm_page_size]; + ++ if (! dirty && ! kcopy) ++ { ++ /* Prepare notified array. */ ++ for (i = 0; i < npages; i++) ++ notified[i] = (p->notify_on_evict ++ && ! (pm_entries[i] & PM_PAGEINWAIT)); ++ ++ _pager_release_seqno (p, seqno); ++ goto notify; ++ } ++ ++ if (! dirty) ++ { ++ _pager_allow_termination (p); ++ goto release_out; ++ } ++ + /* Make sure there are no other in-progress writes for any of these + pages before we begin. This imposes a little more serialization + than we really have to require (because *all* future writes on +@@ -120,10 +140,6 @@ _pager_do_write_request (mach_port_t obj + for (i = 0; i < npages; i++) + pm_entries[i] |= PM_PAGINGOUT | PM_INIT; + +- if (!kcopy) +- for (i = 0; i < npages; i++) +- pm_entries[i] &= ~PM_INCORE; +- + /* If this write occurs while a lock is pending, record + it. We have to keep this list because a lock request + might come in while we do the I/O; in that case there +@@ -163,7 +179,10 @@ _pager_do_write_request (mach_port_t obj + for (i = 0; i < npages; i++) + { + if (omitdata & (1 << i)) +- continue; ++ { ++ notified[i] = 0; ++ continue; ++ } + + if (pm_entries[i] & PM_WRITEWAIT) + wakeup = 1; +@@ -179,14 +198,22 @@ _pager_do_write_request (mach_port_t obj + pm_entries[i] |= PM_INVALID; + + if (pm_entries[i] & PM_PAGEINWAIT) +- memory_object_data_supply (p->memobjcntl, +- offset + (vm_page_size * i), +- data + (vm_page_size * i), +- vm_page_size, 1, +- VM_PROT_NONE, 0, MACH_PORT_NULL); ++ { ++ memory_object_data_supply (p->memobjcntl, ++ offset + (vm_page_size * i), ++ data + (vm_page_size * i), ++ vm_page_size, 1, ++ VM_PROT_NONE, 0, MACH_PORT_NULL); ++ notified[i] = 0; ++ } + else +- munmap ((caddr_t) (data + (vm_page_size * i)), +- vm_page_size); ++ { ++ munmap ((caddr_t) (data + (vm_page_size * i)), ++ vm_page_size); ++ notified[i] = (! kcopy && p->notify_on_evict); ++ if (! kcopy) ++ pm_entries[i] &= ~PM_INCORE; ++ } + + pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT); + } +@@ -198,10 +225,29 @@ _pager_do_write_request (mach_port_t obj + if (wakeup) + condition_broadcast (&p->wakeup); + ++ notify: + _pager_allow_termination (p); +- + mutex_unlock (&p->interlock); + ++ for (i = 0; i < npages; i++) ++ { ++ assert (notified[i] == 0 || notified[i] == 1); ++ if (notified[i]) ++ { ++ short *pm_entry = &pm_entries[i]; ++ ++ /* Do notify user. */ ++ pager_notify_evict (p->upi, offset + (i * vm_page_size)); ++ ++ /* Clear any error that is left. Notification on eviction ++ is used only to change association of page, so any ++ error may no longer be valid. */ ++ mutex_lock (&p->interlock); ++ *pm_entry = SET_PM_ERROR (SET_PM_NEXTERROR (*pm_entry, 0), 0); ++ mutex_unlock (&p->interlock); ++ } ++ } ++ + ports_port_deref (p); + return 0; + +--- a/libpager/pager-create.c ++++ b/libpager/pager-create.c +@@ -22,7 +22,8 @@ struct pager * + pager_create (struct user_pager_info *upi, + struct port_bucket *bucket, + boolean_t may_cache, +- memory_object_copy_strategy_t copy_strategy) ++ memory_object_copy_strategy_t copy_strategy, ++ boolean_t notify_on_evict) + { + struct pager *p; + +@@ -38,6 +39,7 @@ pager_create (struct user_pager_info *up + p->attribute_requests = 0; + p->may_cache = may_cache; + p->copy_strategy = copy_strategy; ++ p->notify_on_evict = notify_on_evict; + p->memobjcntl = MACH_PORT_NULL; + p->memobjname = MACH_PORT_NULL; + p->seqno = -1; +--- a/libpager/pager.h ++++ b/libpager/pager.h +@@ -32,18 +32,21 @@ int pager_demuxer (mach_msg_header_t *in + mach_msg_header_t *outp); + + /* Create a new pager. The pager will have a port created for it +- (using libports, in BUCKET) and will be immediately ready +- to receive requests. U_PAGER will be provided to later calls to ++ (using libports, in BUCKET) and will be immediately ready to ++ receive requests. U_PAGER will be provided to later calls to + pager_find_address. The pager will have one user reference + created. MAY_CACHE and COPY_STRATEGY are the original values of +- those attributes as for memory_object_ready. Users may create +- references to pagers by use of the relevant ports library +- functions. On errors, return null and set errno. */ ++ those attributes as for memory_object_ready. If NOTIFY_ON_EVICT is ++ non-zero, pager_notify_evict user callback will be called when page ++ is evicted. Users may create references to pagers by use of the ++ relevant ports library functions. On errors, return null and set ++ errno. */ + struct pager * + pager_create (struct user_pager_info *u_pager, + struct port_bucket *bucket, + boolean_t may_cache, +- memory_object_copy_strategy_t copy_strategy); ++ memory_object_copy_strategy_t copy_strategy, ++ boolean_t notify_on_evict); + + /* Return the user_pager_info struct associated with a pager. */ + struct user_pager_info * +@@ -110,7 +113,7 @@ pager_offer_page (struct pager *pager, + /* Change the attributes of the memory object underlying pager PAGER. + Args MAY_CACHE and COPY_STRATEGY are as for + memory_object_change_atributes. Wait for the kernel to report completion +- off WAIT is set.*/ ++ iff WAIT is set. */ + void + pager_change_attributes (struct pager *pager, + boolean_t may_cache, +@@ -172,6 +175,18 @@ error_t + pager_unlock_page (struct user_pager_info *pager, + vm_offset_t address); + ++/* The user must define this function. It is used when you want be ++ able to change association of pages to backing store. To use it, ++ pass non-zero value in NOTIFY_ON_EVICT when pager is created with ++ pager_create. You can change association of page only when ++ pager_notify_evict has been called and you haven't touched page ++ content after that. Note there is a possibility that a page is ++ evicted, but user is not notified about that. The user should be ++ able to handle this case. */ ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page); ++ + /* The user must define this function. It should report back (in + *OFFSET and *SIZE the minimum valid address the pager will accept + and the size of the object. */ +--- a/libpager/priv.h ++++ b/libpager/priv.h +@@ -45,6 +45,7 @@ struct pager + + boolean_t may_cache; + memory_object_copy_strategy_t copy_strategy; ++ boolean_t notify_on_evict; + + /* Interface ports */ + memory_object_control_t memobjcntl; +--- a/storeio/pager.c ++++ b/storeio/pager.c +@@ -109,6 +109,13 @@ pager_unlock_page (struct user_pager_inf + return 0; + } + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ assert (!"unrequested notification on eviction"); ++} ++ + /* The user must define this function. It should report back (in + *OFFSET and *SIZE the minimum valid address the pager will accept + and the size of the object. */ +@@ -232,7 +239,7 @@ dev_get_memory_object (struct dev *dev, + { + dev->pager = + pager_create ((struct user_pager_info *)dev, pager_port_bucket, +- 1, MEMORY_OBJECT_COPY_DELAY); ++ 1, MEMORY_OBJECT_COPY_DELAY, 0); + if (dev->pager == NULL) + { + mutex_unlock (&dev->pager_lock); +--- a/tmpfs/pager-stubs.c ++++ b/tmpfs/pager-stubs.c +@@ -57,6 +57,14 @@ pager_unlock_page (struct user_pager_inf + return EIEIO; + } + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ abort(); ++} ++ ++ + /* The user must define this function. It should report back (in + *OFFSET and *SIZE the minimum valid address the pager will accept + and the size of the object. */ +--- a/ufs/pager.c ++++ b/ufs/pager.c +@@ -425,6 +425,13 @@ pager_unlock_page (struct user_pager_inf + return err; + } + ++void ++pager_notify_evict (struct user_pager_info *pager, ++ vm_offset_t page) ++{ ++ assert (!"unrequested notification on eviction"); ++} ++ + /* Implement the pager_report_extent callback from the pager library. See + <hurd/pager.h> for the interface description. */ + inline error_t +@@ -477,7 +484,7 @@ create_disk_pager (void) + upi->type = DISK; + upi->np = 0; + pager_bucket = ports_create_bucket (); +- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size, ++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0, store->size, + &disk_image); + upi->p = diskfs_disk_pager; + } +@@ -570,7 +577,7 @@ diskfs_get_filemap (struct node *np, vm_ + upi->unlocked_pagein_length = 0; + diskfs_nref_light (np); + upi->p = pager_create (upi, pager_bucket, +- MAY_CACHE, MEMORY_OBJECT_COPY_DELAY); ++ MAY_CACHE, MEMORY_OBJECT_COPY_DELAY, 0); + if (upi->p == 0) + { + diskfs_nrele_light (np); diff --git a/debian/patches/extern_inline_fix.patch b/debian/patches/extern_inline_fix.patch new file mode 100644 index 00000000..8423de30 --- /dev/null +++ b/debian/patches/extern_inline_fix.patch @@ -0,0 +1,734 @@ +Use libc's __extern_inline which works properly according to optimization flags +--- + libdiskfs/diskfs.h | 17 ++++++---- + libpipe/pipe.h | 74 ++++++++++++++++++++++++++++++++------------ + libpipe/pq.h | 57 ++++++++++++++++++++++++++------- + libshouldbeinlibc/idvec.h | 29 ++++++++++++----- + libshouldbeinlibc/maptime.h | 13 ++++--- + libshouldbeinlibc/ugids.h | 25 ++++++++++---- + libstore/store.h | 13 ++++--- + libthreads/rwlock.h | 27 +++++++++++----- + 8 files changed, 184 insertions(+), 71 deletions(-) + +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -27,10 +27,7 @@ + #include <hurd/fshelp.h> + #include <hurd/iohelp.h> + #include <idvec.h> +- +-#ifndef DISKFS_EXTERN_INLINE +-#define DISKFS_EXTERN_INLINE extern inline +-#endif ++#include <features.h> + + /* Each user port referring to a file points to one of these + (with the aid of the ports library). */ +@@ -781,10 +778,16 @@ error_t diskfs_start_protid (struct pero + the user to install is USER. */ + void diskfs_finish_protid (struct protid *cred, struct iouser *user); + ++extern struct protid * diskfs_begin_using_protid_port (file_t port); ++ ++extern void diskfs_end_using_protid_port (struct protid *cred); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Called by MiG to translate ports into struct protid *. + fsmutations.h arranges for this to happen for the io and + fs interfaces. */ +-DISKFS_EXTERN_INLINE struct protid * ++__extern_inline struct protid * + diskfs_begin_using_protid_port (file_t port) + { + return ports_lookup_port (diskfs_port_bucket, port, diskfs_protid_class); +@@ -793,13 +796,15 @@ diskfs_begin_using_protid_port (file_t p + /* Called by MiG after server routines have been run; this + balances begin_using_protid_port, and is arranged for the io + and fs interfaces by fsmutations.h. */ +-DISKFS_EXTERN_INLINE void ++__extern_inline void + diskfs_end_using_protid_port (struct protid *cred) + { + if (cred) + ports_port_deref (cred); + } + ++# endif /* Use extern inlines. */ ++ + /* Called when a protid CRED has no more references. (Because references\ + to protids are maintained by the port management library, this is + installed in the clean routines list.) The ports library will +--- a/libpipe/pipe.h ++++ b/libpipe/pipe.h +@@ -24,13 +24,10 @@ + #define EWOULDBLOCK EAGAIN /* XXX */ + + #include <cthreads.h> /* For conditions & mutexes */ ++#include <features.h> + + #include "pq.h" + +-#ifndef PIPE_EI +-#define PIPE_EI extern inline +-#endif +- + + /* A description of a class of pipes and how to operate on them. */ + struct pipe_class +@@ -107,9 +104,24 @@ struct pipe + /* Pipe flags. */ + #define PIPE_BROKEN 0x1 /* This pipe isn't connected. */ + ++ ++extern size_t pipe_readable (struct pipe *pipe, int data_only); ++ ++extern int pipe_is_readable (struct pipe *pipe, int data_only); ++ ++extern error_t pipe_wait_readable (struct pipe *pipe, int noblock, int data_only); ++ ++extern error_t pipe_select_readable (struct pipe *pipe, int data_only); ++ ++extern error_t pipe_wait_writable (struct pipe *pipe, int noblock); ++ ++extern error_t pipe_select_writable (struct pipe *pipe); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns the number of characters quickly readable from PIPE. If DATA_ONLY + is true, then `control' packets are ignored. */ +-PIPE_EI size_t ++__extern_inline size_t + pipe_readable (struct pipe *pipe, int data_only) + { + size_t readable = 0; +@@ -128,7 +140,7 @@ pipe_readable (struct pipe *pipe, int da + then `control' packets are ignored. Note that this is different than + (pipe_readable (PIPE) > 0) in the case where a control packet containing + only ports is present. */ +-PIPE_EI int ++__extern_inline int + pipe_is_readable (struct pipe *pipe, int data_only) + { + struct pq *pq = pipe->queue; +@@ -143,7 +155,7 @@ pipe_is_readable (struct pipe *pipe, int + this operation will return EWOULDBLOCK instead of blocking when no data is + immediately available. If DATA_ONLY is true, then `control' packets are + ignored. */ +-PIPE_EI error_t ++__extern_inline error_t + pipe_wait_readable (struct pipe *pipe, int noblock, int data_only) + { + while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN)) +@@ -160,7 +172,7 @@ pipe_wait_readable (struct pipe *pipe, i + returns once threads waiting using pipe_wait_readable have been woken and + given a chance to read, and if there is still data available thereafter. + If DATA_ONLY is true, then `control' packets are ignored. */ +-PIPE_EI error_t ++__extern_inline error_t + pipe_select_readable (struct pipe *pipe, int data_only) + { + while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN)) +@@ -172,7 +184,7 @@ pipe_select_readable (struct pipe *pipe, + /* Block until data can be written to PIPE. If NOBLOCK is true, then + EWOULDBLOCK is returned instead of blocking if this can't be done + immediately. */ +-PIPE_EI error_t ++__extern_inline error_t + pipe_wait_writable (struct pipe *pipe, int noblock) + { + size_t limit = pipe->write_limit; +@@ -193,7 +205,7 @@ pipe_wait_writable (struct pipe *pipe, i + /* Block until some data can be written to PIPE. This call only returns once + threads waiting using pipe_wait_writable have been woken and given a + chance to write, and if there is still space available thereafter. */ +-PIPE_EI error_t ++__extern_inline error_t + pipe_select_writable (struct pipe *pipe) + { + size_t limit = pipe->write_limit; +@@ -203,6 +215,8 @@ pipe_select_writable (struct pipe *pipe) + return 0; + } + ++# endif /* Use extern inlines. */ ++ + /* Creates a new pipe of class CLASS and returns it in RESULT. */ + error_t pipe_create (struct pipe_class *class, struct pipe **pipe); + +@@ -223,8 +237,28 @@ void _pipe_no_readers (struct pipe *pipe + should be locked. */ + void _pipe_no_writers (struct pipe *pipe); + ++extern void pipe_acquire_reader (struct pipe *pipe); ++ ++extern void pipe_acquire_writer (struct pipe *pipe); ++ ++extern void pipe_release_reader (struct pipe *pipe); ++ ++extern void pipe_release_writer (struct pipe *pipe); ++ ++extern void pipe_add_reader (struct pipe *pipe); ++ ++extern void pipe_add_writer (struct pipe *pipe); ++ ++extern void pipe_remove_reader (struct pipe *pipe); ++ ++extern void pipe_remove_writer (struct pipe *pipe); ++ ++extern void pipe_drain (struct pipe *pipe); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Lock PIPE and increment its readers count. */ +-PIPE_EI void ++__extern_inline void + pipe_acquire_reader (struct pipe *pipe) + { + mutex_lock (&pipe->lock); +@@ -233,7 +267,7 @@ pipe_acquire_reader (struct pipe *pipe) + } + + /* Lock PIPE and increment its writers count. */ +-PIPE_EI void ++__extern_inline void + pipe_acquire_writer (struct pipe *pipe) + { + mutex_lock (&pipe->lock); +@@ -243,7 +277,7 @@ pipe_acquire_writer (struct pipe *pipe) + + /* Decrement PIPE's (which should be locked) reader count and unlock it. If + there are no more refs to PIPE, it will be destroyed. */ +-PIPE_EI void ++__extern_inline void + pipe_release_reader (struct pipe *pipe) + { + if (--pipe->readers == 0) +@@ -254,7 +288,7 @@ pipe_release_reader (struct pipe *pipe) + + /* Decrement PIPE's (which should be locked) writer count and unlock it. If + there are no more refs to PIPE, it will be destroyed. */ +-PIPE_EI void ++__extern_inline void + pipe_release_writer (struct pipe *pipe) + { + if (--pipe->writers == 0) +@@ -264,7 +298,7 @@ pipe_release_writer (struct pipe *pipe) + } + + /* Increment PIPE's reader count. PIPE should be unlocked. */ +-PIPE_EI void ++__extern_inline void + pipe_add_reader (struct pipe *pipe) + { + pipe_acquire_reader (pipe); +@@ -272,7 +306,7 @@ pipe_add_reader (struct pipe *pipe) + } + + /* Increment PIPE's writer count. PIPE should be unlocked. */ +-PIPE_EI void ++__extern_inline void + pipe_add_writer (struct pipe *pipe) + { + pipe_acquire_writer (pipe); +@@ -281,7 +315,7 @@ pipe_add_writer (struct pipe *pipe) + + /* Decrement PIPE's (which should be unlocked) reader count and unlock it. If + there are no more refs to PIPE, it will be destroyed. */ +-PIPE_EI void ++__extern_inline void + pipe_remove_reader (struct pipe *pipe) + { + mutex_lock (&pipe->lock); +@@ -290,7 +324,7 @@ pipe_remove_reader (struct pipe *pipe) + + /* Decrement PIPE's (which should be unlocked) writer count and unlock it. If + there are no more refs to PIPE, it will be destroyed. */ +-PIPE_EI void ++__extern_inline void + pipe_remove_writer (struct pipe *pipe) + { + mutex_lock (&pipe->lock); +@@ -298,12 +332,14 @@ pipe_remove_writer (struct pipe *pipe) + } + + /* Empty out PIPE of any data. PIPE should be locked. */ +-PIPE_EI void ++__extern_inline void + pipe_drain (struct pipe *pipe) + { + pq_drain (pipe->queue); + } + ++# endif /* Use extern inlines. */ ++ + /* Writes up to LEN bytes of DATA, to PIPE, which should be locked, and + returns the amount written in AMOUNT. If present, the information in + CONTROL & PORTS is written in a preceding control packet. If an error is +--- a/libpipe/pq.h ++++ b/libpipe/pq.h +@@ -25,10 +25,7 @@ + #include <stddef.h> /* for size_t */ + #include <string.h> + #include <mach/mach.h> +- +-#ifndef PQ_EI +-#define PQ_EI extern inline +-#endif ++#include <features.h> + + + struct packet +@@ -70,13 +67,19 @@ error_t packet_set_ports (struct packet + /* If PACKET has any ports, deallocates them. */ + void packet_dealloc_ports (struct packet *packet); + ++extern size_t packet_readable (struct packet *packet); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns the number of bytes of data in PACKET. */ +-PQ_EI size_t ++__extern_inline size_t + packet_readable (struct packet *packet) + { + return packet->buf_end - packet->buf_start; + } + ++# endif /* Use extern inlines. */ ++ + /* Append the bytes in DATA, of length DATA_LEN, to what's already in PACKET, + and return the amount appended in AMOUNT if that's not the null pointer. */ + error_t packet_write (struct packet *packet, +@@ -94,14 +97,20 @@ error_t packet_read (struct packet *pack + error_t packet_read_ports (struct packet *packet, + mach_port_t **ports, size_t *num_ports); + ++extern void packet_read_source (struct packet *packet, void **source); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Return the source addressd in PACKET in SOURCE, deallocating it from + PACKET. */ +-PQ_EI void ++__extern_inline void + packet_read_source (struct packet *packet, void **source) + { + *source = packet->source; + packet->source = 0; + } ++ ++# endif /* Use extern inlines. */ + + /* The packet size above which we start to do things differently to avoid + copying around data. */ +@@ -125,9 +134,17 @@ int packet_extend (struct packet *packet + returned. */ + error_t packet_realloc (struct packet *packet, size_t new_len); + ++extern int packet_fit (struct packet *packet, size_t amount); ++ ++extern error_t packet_ensure (struct packet *packet, size_t amount); ++ ++extern int packet_ensure_efficiently (struct packet *packet, size_t amount); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Try to make space in PACKET for AMOUNT more bytes without growing the + buffer, returning true if we could do it. */ +-PQ_EI int ++__extern_inline int + packet_fit (struct packet *packet, size_t amount) + { + char *buf = packet->buf, *end = packet->buf_end; +@@ -159,7 +176,7 @@ packet_fit (struct packet *packet, size_ + + /* Make sure that PACKET has room for at least AMOUNT more bytes, or return + the reason why not. */ +-PQ_EI error_t ++__extern_inline error_t + packet_ensure (struct packet *packet, size_t amount) + { + if (! packet_fit (packet, amount)) +@@ -176,7 +193,7 @@ packet_ensure (struct packet *packet, si + it can be done efficiently, e.g., the packet can be grown in place, rather + than moving the contents (or there is little enough data so that copying + it is OK). True is returned if room was made, false otherwise. */ +-PQ_EI int ++__extern_inline int + packet_ensure_efficiently (struct packet *packet, size_t amount) + { + if (! packet_fit (packet, amount)) +@@ -189,6 +206,8 @@ packet_ensure_efficiently (struct packet + } + return 0; + } ++ ++# endif /* Use extern inlines. */ + + struct pq + { +@@ -201,10 +220,14 @@ struct pq + the packet, or deallocated by calling pipe_dealloc_addr. */ + struct packet *pq_queue (struct pq *pq, unsigned type, void *source); + ++extern struct packet * pq_tail (struct pq *pq, unsigned type, void *source); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns the tail of the packet queue PQ, which may mean pushing a new + packet if TYPE and SOURCE do not match the current tail, or this is the + first packet. */ +-PQ_EI struct packet * ++__extern_inline struct packet * + pq_tail (struct pq *pq, unsigned type, void *source) + { + struct packet *tail = pq->tail; +@@ -214,16 +237,24 @@ pq_tail (struct pq *pq, unsigned type, v + return tail; + } + ++# endif /* Use extern inlines. */ ++ + /* Remove the first packet (if any) in PQ, deallocating any resources it + holds. True is returned if a packet was found, false otherwise. */ + int pq_dequeue (struct pq *pq); + ++extern struct packet * pq_head (struct pq *pq, unsigned type, void *source); ++ ++extern struct packet * pq_next (struct pq *pq, unsigned type, void *source); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns the next available packet in PQ, without removing it from the + queue, or NULL if there is none, or the next packet isn't appropiate. + A packet is inappropiate if SOURCE is non-NULL its source field doesn't + match it, or TYPE is non-NULL and the packet's type field doesn't match + it. */ +-PQ_EI struct packet * ++__extern_inline struct packet * + pq_head (struct pq *pq, unsigned type, void *source) + { + struct packet *head = pq->head; +@@ -237,7 +268,7 @@ pq_head (struct pq *pq, unsigned type, v + } + + /* The same as pq_head, but first discards the head of the queue. */ +-PQ_EI struct packet * ++__extern_inline struct packet * + pq_next (struct pq *pq, unsigned type, void *source) + { + if (!pq->head) +@@ -246,6 +277,8 @@ pq_next (struct pq *pq, unsigned type, v + return pq_head (pq, type, source); + } + ++# endif /* Use extern inlines. */ ++ + /* Dequeues all packets in PQ. */ + void pq_drain (struct pq *pq); + +--- a/libshouldbeinlibc/idvec.h ++++ b/libshouldbeinlibc/idvec.h +@@ -24,10 +24,7 @@ + #include <hurd/hurd_types.h> + #include <errno.h> + #include <string.h> +- +-#ifndef IDVEC_EI +-#define IDVEC_EI extern inline +-#endif ++#include <features.h> + + struct idvec + { +@@ -50,22 +47,30 @@ void idvec_free_wrapper (struct idvec *i + /* Free IDVEC and any storage associated with it. */ + void idvec_free (struct idvec *idvec); + ++extern void idvec_clear (struct idvec *idvec); ++ ++extern int idvec_is_empty (const struct idvec *idvec); ++ ++extern int idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Mark IDVEC as not containing any ids. */ +-IDVEC_EI void ++__extern_inline void + idvec_clear (struct idvec *idvec) + { + idvec->num = 0; + } + + /* Returns true if IDVEC contains no ids. */ +-IDVEC_EI int ++__extern_inline int + idvec_is_empty (const struct idvec *idvec) + { + return idvec->num == 0; + } + + /* Return true if IDVEC1 has contents identical to IDVEC2. */ +-IDVEC_EI int ++__extern_inline int + idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2) + { + size_t num = idvec1->num; +@@ -74,6 +79,8 @@ idvec_equal (const struct idvec *idvec1, + || memcmp (idvec1->ids, idvec2->ids, num * sizeof *idvec1->ids) == 0); + } + ++# endif /* Use extern inlines. */ ++ + /* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus + ensuring that any subsequent ids added won't return a memory allocation + error unless it would result in more ids that NUM. ENOMEM is returned if +@@ -87,13 +94,19 @@ error_t idvec_grow (struct idvec *idvec, + /* Returns true if IDVEC contains ID, at or after position POS. */ + int idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id); + ++extern int idvec_contains (const struct idvec *idvec, uid_t id); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns true if IDVEC contains ID. */ +-IDVEC_EI int ++__extern_inline int + idvec_contains (const struct idvec *idvec, uid_t id) + { + return idvec_tail_contains (idvec, 0, id); + } + ++# endif /* Use extern inlines. */ ++ + /* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't + enough memory, or 0. */ + error_t idvec_insert (struct idvec *idvec, unsigned pos, uid_t id); +--- a/libshouldbeinlibc/maptime.h ++++ b/libshouldbeinlibc/maptime.h +@@ -21,13 +21,10 @@ + #ifndef __MAPTIME_H__ + #define __MAPTIME_H__ + +-#ifndef MAPTIME_EI +-#define MAPTIME_EI extern inline +-#endif +- + #include <mach/time_value.h> + #include <sys/time.h> + #include <errno.h> ++#include <features.h> + + /* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then + the hurd time device DEV_NAME, or "/dev/time" if DEV_NAME is 0, is +@@ -37,8 +34,12 @@ + error_t maptime_map (int use_mach_dev, char *dev_name, + volatile struct mapped_time_value **mtime); + ++extern void maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Read the current time from MTIME into TV. This should be very fast. */ +-MAPTIME_EI void ++__extern_inline void + maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv) + { + do +@@ -49,4 +50,6 @@ maptime_read (volatile struct mapped_tim + while (tv->tv_sec != mtime->check_seconds); + } + ++# endif /* Use extern inlines. */ ++ + #endif /* __MAPTIME_H__ */ +--- a/libshouldbeinlibc/ugids.h ++++ b/libshouldbeinlibc/ugids.h +@@ -23,10 +23,7 @@ + + #include <stdlib.h> /* For inline function stuff. */ + #include <idvec.h> +- +-#ifndef UGIDS_EI +-#define UGIDS_EI extern inline +-#endif ++#include <features.h> + + /* A structure holding a set of the common various types of ids. */ + struct ugids +@@ -47,8 +44,18 @@ struct ugids + /* Return a new ugids structure, or 0 if an allocation error occurs. */ + struct ugids *make_ugids (); + ++extern void ugids_fini (struct ugids *ugids); ++ ++extern void ugids_free (struct ugids *ugids); ++ ++extern int ugids_is_empty (const struct ugids *ugids); ++ ++extern int ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Free all resources used by UGIDS except UGIDS itself. */ +-UGIDS_EI void ++__extern_inline void + ugids_fini (struct ugids *ugids) + { + idvec_fini (&ugids->eff_uids); +@@ -60,7 +67,7 @@ ugids_fini (struct ugids *ugids) + } + + /* Free all resources used by UGIDS. */ +-UGIDS_EI void ++__extern_inline void + ugids_free (struct ugids *ugids) + { + ugids_fini (ugids); +@@ -68,7 +75,7 @@ ugids_free (struct ugids *ugids) + } + + /* Return true if UGIDS contains no ids. */ +-UGIDS_EI int ++__extern_inline int + ugids_is_empty (const struct ugids *ugids) + { + /* We needn't test the imp_*_gids vectors because they are subsets of the +@@ -81,7 +88,7 @@ ugids_is_empty (const struct ugids *ugid + } + + /* Free all resources used by UGIDS except UGIDS itself. */ +-UGIDS_EI int ++__extern_inline int + ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2) + { + return +@@ -93,6 +100,8 @@ ugids_equal (const struct ugids *ugids1, + && idvec_equal (&ugids1->imp_avail_gids, &ugids2->imp_avail_gids); + } + ++# endif /* Use extern inlines. */ ++ + /* Add all ids in NEW to UGIDS. */ + error_t ugids_merge (struct ugids *ugids, const struct ugids *new); + +--- a/libstore/store.h ++++ b/libstore/store.h +@@ -33,10 +33,7 @@ + #include <mach.h> + #include <device/device.h> + #include <hurd/hurd_types.h> +- +-#ifndef STORE_EI +-#define STORE_EI extern inline +-#endif ++#include <features.h> + + + /* Type for addresses inside the store. */ +@@ -270,9 +267,13 @@ error_t store_set_child_flags (struct st + STORE's flags. */ + error_t store_clear_child_flags (struct store *store, int flags); + ++extern int store_is_securely_returnable (struct store *store, int open_flags); ++ ++# ifdef __USE_EXTERN_INLINES ++ + /* Returns true if STORE can safely be returned to a user who has accessed it + via a node using OPEN_FLAGS, without compromising security. */ +-STORE_EI int ++__extern_inline int + store_is_securely_returnable (struct store *store, int open_flags) + { + int flags = store->flags; +@@ -283,6 +284,8 @@ store_is_securely_returnable (struct sto + || (flags & STORE_HARD_READONLY))); + } + ++# endif /* Use extern inlines. */ ++ + /* Fills in the values of the various fields in STORE that are derivable from + the set of runs & the block size. */ + void _store_derive (struct store *store); +--- a/libthreads/rwlock.h ++++ b/libthreads/rwlock.h +@@ -21,6 +21,7 @@ + + #include <cthreads.h> + #include <assert.h> ++#include <features.h> + + struct rwlock + { +@@ -31,12 +32,20 @@ struct rwlock + int readers_waiting; + }; + +-#ifndef RWLOCK_EI +-#define RWLOCK_EI extern inline +-#endif ++extern void rwlock_reader_lock (struct rwlock *lock); ++ ++extern void rwlock_writer_lock (struct rwlock *lock); ++ ++extern void rwlock_reader_unlock (struct rwlock *lock); ++ ++extern void rwlock_writer_unlock (struct rwlock *lock); ++ ++extern void rwlock_init (struct rwlock *lock); ++ ++# ifdef __USE_EXTERN_INLINES + + /* Get a reader lock on reader-writer lock LOCK for disknode DN */ +-RWLOCK_EI void ++__extern_inline void + rwlock_reader_lock (struct rwlock *lock) + { + mutex_lock (&lock->master); +@@ -53,7 +62,7 @@ rwlock_reader_lock (struct rwlock *lock) + } + + /* Get a writer lock on reader-writer lock LOCK for disknode DN */ +-RWLOCK_EI void ++__extern_inline void + rwlock_writer_lock (struct rwlock *lock) + { + mutex_lock (&lock->master); +@@ -70,7 +79,7 @@ rwlock_writer_lock (struct rwlock *lock) + } + + /* Release a reader lock on reader-writer lock LOCK for disknode DN */ +-RWLOCK_EI void ++__extern_inline void + rwlock_reader_unlock (struct rwlock *lock) + { + mutex_lock (&lock->master); +@@ -82,7 +91,7 @@ rwlock_reader_unlock (struct rwlock *loc + } + + /* Release a writer lock on reader-writer lock LOCK for disknode DN */ +-RWLOCK_EI void ++__extern_inline void + rwlock_writer_unlock (struct rwlock *lock) + { + mutex_lock (&lock->master); +@@ -94,7 +103,7 @@ rwlock_writer_unlock (struct rwlock *loc + } + + /* Initialize reader-writer lock LOCK */ +-RWLOCK_EI void ++__extern_inline void + rwlock_init (struct rwlock *lock) + { + mutex_init (&lock->master); +@@ -104,6 +113,8 @@ rwlock_init (struct rwlock *lock) + lock->writers_waiting = 0; + } + ++# endif /* Use extern inlines. */ ++ + #define RWLOCK_INITIALIZER \ + { MUTEX_INITIALIZER, CONDITION_INITIALIZER, 0, 0, 0 } + diff --git a/debian/patches/hurd_console_startup.patch b/debian/patches/hurd_console_startup.patch new file mode 100644 index 00000000..8e9301c8 --- /dev/null +++ b/debian/patches/hurd_console_startup.patch @@ -0,0 +1,32 @@ +Automatically startup the hurd console when enabled. +--- + daemons/runsystem.sh | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/daemons/runsystem.sh ++++ b/daemons/runsystem.sh +@@ -127,10 +127,24 @@ while : ; do + trap "kill -$sig \${runttys_pid}" $sig + done + ++ # Touch the first tty so that the Hurd console is certain to pick it ++ # and not some random other tty. ++ touch /dev/tty1 ++ + # This program reads /etc/ttys and starts the programs it says to. + ${RUNTTYS} & + runttys_pid=$! + ++ # Startup the Hurd console if configured. ++ if [ -e /etc/default/hurd-console ]; then ++ unset DISPLAY KBD KBD_REPEAT MOUSE MOUSE_REPEAT SPEAKER ++ . /etc/default/hurd-console ++ fi ++ if [ "$ENABLE" = "true" ]; then ++ console ${DISPLAY} ${KBD} ${KBD_REPEAT} \ ++ ${SPEAKER} ${MOUSE} ${MOUSE_REPEAT} -d current_vcs -c /dev/vcs ++ fi ++ + # Wait for runttys to die, meanwhile handling trapped signals. + wait + diff --git a/debian/patches/init_try_runsystem.gnu.patch b/debian/patches/init_try_runsystem.gnu.patch new file mode 100644 index 00000000..817a6d84 --- /dev/null +++ b/debian/patches/init_try_runsystem.gnu.patch @@ -0,0 +1,75 @@ +Also try runsystem.gnu +--- + daemons/console-run.c | 7 +++++++ + init/init.c | 24 ++++++++++++++++++++---- + 2 files changed, 27 insertions(+), 4 deletions(-) + +--- a/init/init.c ++++ b/init/init.c +@@ -1082,10 +1082,12 @@ start_child (const char *prog, char **pr + static void + launch_something (const char *why) + { ++ file_t something; + static unsigned int try; + static const char *const tries[] = + { + "/libexec/runsystem", ++ "/libexec/runsystem.gnu", + _PATH_BSHELL, + "/bin/shd", /* XXX */ + }; +@@ -1093,12 +1095,26 @@ launch_something (const char *why) + if (why) + error (0, 0, "%s %s", tries[try - 1], why); + +- if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0) +- return; ++ something = file_name_lookup (tries[try], O_EXEC, 0); ++ if (something != MACH_PORT_NULL) ++ { ++ mach_port_deallocate (mach_task_self (), something); ++ if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0) ++ return; ++ } ++ else ++ try++; + + while (try < sizeof tries / sizeof tries[0]) +- if (start_child (tries[try++], NULL) == 0) +- return; ++ { ++ something = file_name_lookup (tries[try], O_EXEC, 0); ++ if (something != MACH_PORT_NULL) ++ { ++ mach_port_deallocate (mach_task_self (), something); ++ if (start_child (tries[try++], NULL) == 0) ++ return; ++ } ++ } + + crash_system (); + } +--- a/daemons/console-run.c ++++ b/daemons/console-run.c +@@ -49,6 +49,7 @@ int + main (int argc, char **argv) + { + mach_port_t consdev = get_console (); ++ mach_port_t runsystem; + char *consname; + + if (consdev == MACH_PORT_NULL) +@@ -62,6 +63,12 @@ main (int argc, char **argv) + if (argc < 2) + error (1, 0, "Usage: %s PROGRAM [ARG...]", program_invocation_short_name); + ++ /* Check whether runsystem exists before opening a console for it. */ ++ runsystem = file_name_lookup (argv[1], O_RDONLY, 0); ++ if (runsystem == MACH_PORT_NULL) ++ error (127, errno, "cannot open file `%s' for execution", argv[1]); ++ mach_port_deallocate (mach_task_self (), runsystem); ++ + if (open_console (&consname)) + setenv ("FALLBACK_CONSOLE", consname, 1); + diff --git a/debian/patches/install-msgids.diff b/debian/patches/install-msgids.diff new file mode 100644 index 00000000..305e0e0d --- /dev/null +++ b/debian/patches/install-msgids.diff @@ -0,0 +1,36 @@ +2005-08-25 Alfred M. Szmidt <ams@gnu.org> + + * Makefile (MSGIDS): New variable. + (all, install-msgids, $(datadir)/msgids): New targets. + (install): Specify install-header and install-msgids as + prerequisites. + +--- + hurd/Makefile | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/hurd/Makefile ++++ b/hurd/Makefile +@@ -22,15 +22,20 @@ DIST_FILES = subsystems $(notdir $(hdrs) + + INSTHDRS = hurd_types.h version.h ioctl_types.h paths.h shared.h console.h \ + $(notdir $(wildcard $(srcdir)/*.defs)) ++MSGIDS := hurd.msgids $(patsubst %.defs,%.msgids,$(filter %.defs,$(INSTHDRS))) + + include ../Makeconf + +-install-headers install: $(includedir)/hurd \ ++all: $(MSGIDS) ++ ++install: install-msgids install-headers ++install-headers: $(includedir)/hurd \ + $(addprefix $(includedir)/hurd/,$(INSTHDRS)) ++install-msgids: $(MSGIDS) $(datadir)/msgids; $(INSTALL_DATA) $^ + + $(includedir)/hurd/%: $(srcdir)/%; $(INSTALL_DATA) $< $@ + +-$(includedir)/hurd:;mkdir -p $@ ++$(datadir)/msgids $(includedir)/hurd:;mkdir -p $@ + + %.msgids: $(srcdir)/%.defs + if grep -q '^subsystem' $<; \ diff --git a/debian/patches/libdiskfs-rename.patch b/debian/patches/libdiskfs-rename.patch new file mode 100644 index 00000000..2809e562 --- /dev/null +++ b/debian/patches/libdiskfs-rename.patch @@ -0,0 +1,27 @@ +Avoid a mutex deadlock by simply preventing '.' or '..' in source or target +operands. +--- + libdiskfs/dir-rename.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/libdiskfs/dir-rename.c ++++ b/libdiskfs/dir-rename.c +@@ -19,6 +19,7 @@ + + #include "priv.h" + #include "fs_S.h" ++#include <string.h> + + /* To avoid races in checkpath, and to prevent a directory from being + simultaneously renamed by two processes, we serialize all renames of +@@ -44,6 +45,10 @@ diskfs_S_dir_rename (struct protid *from + if (! tocred) + return EXDEV; + ++ if (!strcmp (fromname, ".") || !strcmp (fromname, "..") ++ || !strcmp (toname, ".") || !strcmp (toname, "..")) ++ return EINVAL; ++ + if (tocred->po->shadow_root != fromcred->po->shadow_root) + /* Same translator, but in different shadow trees. */ + return EXDEV; diff --git a/debian/patches/libpager_update_seqno.patch b/debian/patches/libpager_update_seqno.patch new file mode 100644 index 00000000..6246e8a1 --- /dev/null +++ b/debian/patches/libpager_update_seqno.patch @@ -0,0 +1,140 @@ +2005-08-10 Sergio Lopez <koro@sinrega.org> + + * seqnos.c (_pager_stubs_update_seqno): New function. + * priv.h (_pager_stubs_update_seqno): New function. + + * notify-stubs.c (_pager_do_seqnos_mach_notify_port_deleted): + Call _pager_stubs_update_seqno to properly update seqno. + (_pager_do_seqnos_mach_notify_msg_accepted): Likewise. + (_pager_do_seqnos_mach_notify_port_destroyed): Likewise. + (_pager_do_seqnos_mach_notify_send_once): Likewise. + (_pager_do_seqnos_mach_notify_dead_name): Likewise. + * stubs.c (_pager_seqnos_memory_object_data_write): Likewise. + (_pager_seqnos_memory_object_supply_completed): Likewise. + +--- + libpager/notify-stubs.c | 6 ++++++ + libpager/priv.h | 1 + + libpager/seqnos.c | 22 ++++++++++++++++++++++ + libpager/stubs.c | 9 +++++++++ + 4 files changed, 38 insertions(+) + +--- a/libpager/notify-stubs.c ++++ b/libpager/notify-stubs.c +@@ -18,6 +18,7 @@ + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + ++#include "priv.h" + #include "notify_S.h" + #include <errno.h> + +@@ -29,6 +30,7 @@ _pager_do_seqnos_mach_notify_port_delete + mach_port_t name + __attribute__ ((unused))) + { ++ _pager_stubs_update_seqno (notify, seqno); + return 0; + } + +@@ -40,6 +42,7 @@ _pager_do_seqnos_mach_notify_msg_accepte + mach_port_t name + __attribute__ ((unused))) + { ++ _pager_stubs_update_seqno (notify, seqno); + return 0; + } + +@@ -51,6 +54,7 @@ _pager_do_seqnos_mach_notify_port_destro + mach_port_t name + __attribute__ ((unused))) + { ++ _pager_stubs_update_seqno (notify, seqno); + return 0; + } + +@@ -60,6 +64,7 @@ _pager_do_seqnos_mach_notify_send_once ( + mach_port_seqno_t seqno + __attribute__ ((unused))) + { ++ _pager_stubs_update_seqno (notify, seqno); + return 0; + } + +@@ -71,5 +76,6 @@ _pager_do_seqnos_mach_notify_dead_name ( + mach_port_t name + __attribute__ ((unused))) + { ++ _pager_stubs_update_seqno (notify, seqno); + return 0; + } +--- a/libpager/priv.h ++++ b/libpager/priv.h +@@ -134,6 +134,7 @@ struct port_class *_pager_class; + + void _pager_wait_for_seqno (struct pager *, int); + void _pager_release_seqno (struct pager *, int); ++void _pager_stubs_update_seqno (mach_port_t, int); + void _pager_block_termination (struct pager *); + void _pager_allow_termination (struct pager *); + error_t _pager_pagemap_resize (struct pager *, vm_address_t); +--- a/libpager/seqnos.c ++++ b/libpager/seqnos.c +@@ -47,3 +47,25 @@ _pager_release_seqno (struct pager *p, + condition_broadcast (&p->wakeup); + } + } ++ ++ ++/* This function is called by stub functions to properly update ++ seqno. */ ++void ++_pager_stubs_update_seqno (mach_port_t object, ++ int seqno) ++{ ++ struct pager *p; ++ ++ p = ports_lookup_port (0, object, _pager_class); ++ if (p) ++ { ++ mutex_lock (&p->interlock); ++ _pager_wait_for_seqno (p, seqno); ++ _pager_release_seqno (p, seqno); ++ mutex_unlock (&p->interlock); ++ ++ ports_port_deref (p); ++ } ++} ++ +--- a/libpager/stubs.c ++++ b/libpager/stubs.c +@@ -29,6 +29,9 @@ _pager_seqnos_memory_object_copy (mach_p + mach_port_t new) + { + printf ("m_o_copy called\n"); ++ ++ _pager_stubs_update_seqno (old, seq); ++ + return EOPNOTSUPP; + } + +@@ -41,6 +44,9 @@ _pager_seqnos_memory_object_data_write ( + vm_size_t data_cnt) + { + printf ("m_o_data_write called\n"); ++ ++ _pager_stubs_update_seqno (old, seq); ++ + return EOPNOTSUPP; + } + +@@ -54,6 +60,9 @@ _pager_seqnos_memory_object_supply_compl + vm_offset_t err_off) + { + printf ("m_o_supply_completed called\n"); ++ ++ _pager_stubs_update_seqno (obj, seq); ++ + return EOPNOTSUPP; + } + diff --git a/debian/patches/libports_stability.patch b/debian/patches/libports_stability.patch new file mode 100644 index 00000000..84edc491 --- /dev/null +++ b/debian/patches/libports_stability.patch @@ -0,0 +1,18 @@ +Ideally we should be able to time out and see translators go away automatically, +however it makes all threads often wake at the same time and overload Mach. + +--- + libports/manage-multithread.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/libports/manage-multithread.c ++++ b/libports/manage-multithread.c +@@ -157,6 +157,8 @@ ports_manage_port_operations_multithread + return 0; + } + ++ thread_timeout = global_timeout = 0; /* XXX */ ++ + nreqthreads = 1; + totalthreads = 1; + thread_function (1); diff --git a/debian/patches/libpthread_cancel_init.patch b/debian/patches/libpthread_cancel_init.patch new file mode 100644 index 00000000..36351c15 --- /dev/null +++ b/debian/patches/libpthread_cancel_init.patch @@ -0,0 +1,29 @@ +commit d69e38ee77536912308212945cfb0b6abe93cef0 +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Tue Oct 13 20:15:08 2009 +0200 + + Fix pthread_cleanup_push old-gcc-style initializer + + sysdeps/generic/bits/cancelation.h (__pthread_cleanup_push): For better + portability to various compilation flags, use standard initializer for + struct __pthread_cancelation_handler __handler instead of old-gcc-style. + +--- + libpthread/sysdeps/generic/bits/cancelation.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/libpthread/sysdeps/generic/bits/cancelation.h ++++ b/libpthread/sysdeps/generic/bits/cancelation.h +@@ -38,9 +38,9 @@ struct __pthread_cancelation_handler **_ + = __pthread_get_cleanup_stack (); \ + struct __pthread_cancelation_handler __handler = \ + { \ +- handler: (rt), \ +- arg: (rtarg), \ +- next: *__handlers \ ++ (rt), \ ++ (rtarg), \ ++ *__handlers \ + }; \ + *__handlers = &__handler; + diff --git a/debian/patches/libpthread_fix.patch b/debian/patches/libpthread_fix.patch new file mode 100644 index 00000000..56e03850 --- /dev/null +++ b/debian/patches/libpthread_fix.patch @@ -0,0 +1,75 @@ +Temporary patch from Thomas Schwinge to fix libpthread bugs. + +--- + libpthread/sysdeps/mach/hurd/pt-init-specific.c | 29 ++++++++++++++++++++++++ + libpthread/sysdeps/mach/pt-thread-dealloc.c | 2 + + libpthread/sysdeps/mach/pt-thread-halt.c | 19 ++++++++++++++- + 3 files changed, 48 insertions(+), 2 deletions(-) + +--- a/libpthread/sysdeps/mach/pt-thread-dealloc.c ++++ b/libpthread/sysdeps/mach/pt-thread-dealloc.c +@@ -38,4 +38,6 @@ __pthread_thread_dealloc (struct __pthre + assert. */ + __mach_port_destroy (__mach_task_self (), + thread->wakeupmsg.msgh_remote_port); ++ ++ thread->have_kernel_resources = 0; + } +--- a/libpthread/sysdeps/mach/pt-thread-halt.c ++++ b/libpthread/sysdeps/mach/pt-thread-halt.c +@@ -32,6 +32,21 @@ + void + __pthread_thread_halt (struct __pthread *thread) + { +- error_t err = __thread_terminate (thread->kernel_thread); +- assert_perror (err); ++ if (thread->have_kernel_resources) ++ { ++ if (thread == _pthread_self ()) ++ { ++ while (1) ++ { ++ error_t err = __thread_suspend (thread->kernel_thread); ++ assert_perror (err); ++ assert (! "Failed to suspend self."); ++ } ++ } ++ else ++ { ++ error_t err = __thread_terminate (thread->kernel_thread); ++ assert_perror (err); ++ } ++ } + } +--- /dev/null ++++ b/libpthread/sysdeps/mach/hurd/pt-init-specific.c +@@ -0,0 +1,29 @@ ++/* __pthread_init_specific. Mach version. ++ Copyright (C) 2002, 2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If not, ++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include <pthread.h> ++#include <pt-internal.h> ++ ++error_t ++__pthread_init_specific (struct __pthread *thread) ++{ ++ thread->thread_specifics = 0; ++ thread->have_kernel_resources = 0; ++ return 0; ++} diff --git a/debian/patches/libpthread_kill_0.patch b/debian/patches/libpthread_kill_0.patch new file mode 100644 index 00000000..4aa307dc --- /dev/null +++ b/debian/patches/libpthread_kill_0.patch @@ -0,0 +1,25 @@ +commit fb30b6bbf28d91667dcb9691dfeefffac4f99b82 +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Sun Oct 18 00:24:19 2009 +0200 + + Fix pthread_kill(thread, 0) + + * sysdeps/hurd/pt-kill.c (pthread_kill): Return immediately after checks + without calling _hurd_raise_signal if sig is 0. + +--- + libpthread/sysdeps/hurd/pt-kill.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/libpthread/sysdeps/hurd/pt-kill.c ++++ b/libpthread/sysdeps/hurd/pt-kill.c +@@ -39,6 +39,9 @@ pthread_kill (pthread_t thread, int sig) + ss = _hurd_thread_sigstate (pthread->kernel_thread); + assert (ss); + ++ if (!sig) ++ return 0; ++ + detail.exc = 0; + detail.code = sig; + detail.error = 0; diff --git a/debian/patches/libpthread_mutex_owner.patch b/debian/patches/libpthread_mutex_owner.patch new file mode 100644 index 00000000..466cffae --- /dev/null +++ b/debian/patches/libpthread_mutex_owner.patch @@ -0,0 +1,22 @@ +--- + libpthread/sysdeps/generic/pt-mutex-trylock.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/libpthread/sysdeps/generic/pt-mutex-trylock.c ++++ b/libpthread/sysdeps/generic/pt-mutex-trylock.c +@@ -34,6 +34,7 @@ __pthread_mutex_trylock (struct __pthrea + if (__pthread_spin_trylock (&mutex->__held) == 0) + /* Acquired the lock. */ + { ++#if defined(ALWAYS_TRACK_MUTEX_OWNER) + #ifndef NDEBUG + self = _pthread_self (); + if (self) +@@ -45,6 +46,7 @@ __pthread_mutex_trylock (struct __pthrea + mutex->owner = _pthread_self (); + } + #endif ++#endif + + if (mutex->attr) + switch (mutex->attr->mutex_type) diff --git a/debian/patches/libpthread_recursive_mutex_initializer.patch b/debian/patches/libpthread_recursive_mutex_initializer.patch new file mode 100644 index 00000000..9b0f8d9c --- /dev/null +++ b/debian/patches/libpthread_recursive_mutex_initializer.patch @@ -0,0 +1,297 @@ +Provide more mutex initializers +--- + libpthread/include/pthread/pthread.h | 2 ++ + libpthread/sysdeps/generic/bits/mutex-attr.h | 1 + + libpthread/sysdeps/generic/bits/mutex.h | 10 +++++++++- + libpthread/sysdeps/generic/pt-mutex-destroy.c | 3 ++- + libpthread/sysdeps/generic/pt-mutex-init.c | 11 ++++------- + libpthread/sysdeps/generic/pt-mutex-timedlock.c | 22 ++++++++++++++-------- + libpthread/sysdeps/generic/pt-mutex-transfer-np.c | 11 +++++++++-- + libpthread/sysdeps/generic/pt-mutex-trylock.c | 14 ++++++++++---- + libpthread/sysdeps/generic/pt-mutex-unlock.c | 16 +++++++++++----- + libpthread/sysdeps/generic/pt-mutexattr.c | 8 ++++++++ + 10 files changed, 70 insertions(+), 28 deletions(-) + +--- a/libpthread/include/pthread/pthread.h ++++ b/libpthread/include/pthread/pthread.h +@@ -313,6 +313,8 @@ extern int pthread_mutexattr_settype(pth + /* Static initializer for recursive mutexes. */ + + #ifdef __USE_GNU ++# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ ++ __PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + __PTHREAD_RECURSIVE_MUTEX_INITIALIZER + #endif +--- a/libpthread/sysdeps/generic/pt-mutex-destroy.c ++++ b/libpthread/sysdeps/generic/pt-mutex-destroy.c +@@ -26,7 +26,8 @@ + int + _pthread_mutex_destroy (pthread_mutex_t *mutex) + { +- if (mutex->attr == &__pthread_recursive_mutexattr) ++ if (mutex->attr == __PTHREAD_ERRORCHECK_MUTEXATTR ++ || mutex->attr == __PTHREAD_RECURSIVE_MUTEXATTR) + /* Static attributes. */ + ; + else +--- a/libpthread/sysdeps/generic/pt-mutex-init.c ++++ b/libpthread/sysdeps/generic/pt-mutex-init.c +@@ -35,14 +35,11 @@ _pthread_mutex_init (pthread_mutex_t *mu + /* The default attributes. */ + return 0; + +- if (attr == &__pthread_recursive_mutexattr) +- /* Non-default but known attributes. */ +- { +- mutex->attr = attr; +- return 0; +- } ++ if (! mutex->attr ++ || mutex->attr == __PTHREAD_ERRORCHECK_MUTEXATTR ++ || mutex->attr == __PTHREAD_RECURSIVE_MUTEXATTR) ++ mutex->attr = malloc (sizeof *attr); + +- mutex->attr = malloc (sizeof *attr); + if (! mutex->attr) + return ENOMEM; + +--- a/libpthread/sysdeps/generic/pt-mutex-timedlock.c ++++ b/libpthread/sysdeps/generic/pt-mutex-timedlock.c +@@ -31,6 +31,12 @@ __pthread_mutex_timedlock_internal (stru + const struct timespec *abstime) + { + struct __pthread *self; ++ const struct __pthread_mutexattr *attr = mutex->attr; ++ ++ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR) ++ attr = &__pthread_errorcheck_mutexattr; ++ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR) ++ attr = &__pthread_recursive_mutexattr; + + __pthread_spin_lock (&mutex->__lock); + if (__pthread_spin_trylock (&mutex->__held) == 0) +@@ -50,8 +56,8 @@ __pthread_mutex_timedlock_internal (stru + #endif + #endif + +- if (mutex->attr) +- switch (mutex->attr->mutex_type) ++ if (attr) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_NORMAL: + break; +@@ -75,7 +81,7 @@ __pthread_mutex_timedlock_internal (stru + self = _pthread_self (); + assert (self); + +- if (! mutex->attr || mutex->attr->mutex_type == PTHREAD_MUTEX_NORMAL) ++ if (! attr || attr->mutex_type == PTHREAD_MUTEX_NORMAL) + { + #if defined(ALWAYS_TRACK_MUTEX_OWNER) + assert (mutex->owner != self); +@@ -83,7 +89,7 @@ __pthread_mutex_timedlock_internal (stru + } + else + { +- switch (mutex->attr->mutex_type) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_ERRORCHECK: + if (mutex->owner == self) +@@ -108,7 +114,7 @@ __pthread_mutex_timedlock_internal (stru + } + + #if !defined(ALWAYS_TRACK_MUTEX_OWNER) +- if (mutex->attr && mutex->attr->mutex_type != PTHREAD_MUTEX_NORMAL) ++ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL) + #endif + assert (mutex->owner); + +@@ -147,14 +153,14 @@ __pthread_mutex_timedlock_internal (stru + __pthread_block (self); + + #if !defined(ALWAYS_TRACK_MUTEX_OWNER) +- if (mutex->attr && mutex->attr->mutex_type != PTHREAD_MUTEX_NORMAL) ++ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL) + #endif + { + assert (mutex->owner == self); + } + +- if (mutex->attr) +- switch (mutex->attr->mutex_type) ++ if (attr) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_NORMAL: + break; +--- a/libpthread/sysdeps/generic/pt-mutex-transfer-np.c ++++ b/libpthread/sysdeps/generic/pt-mutex-transfer-np.c +@@ -29,13 +29,20 @@ __pthread_mutex_transfer_np (struct __pt + assert (mutex->owner == _pthread_self ()); + + struct __pthread *thread = __pthread_getid (tid); ++ const struct __pthread_mutexattr *attr = mutex->attr; ++ + if (! thread) + return ESRCH; + + if (thread == _pthread_self ()) + return 0; + +- if (mutex->attr && mutex->attr->mutex_type == PTHREAD_MUTEX_ERRORCHECK) ++ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR) ++ attr = &__pthread_errorcheck_mutexattr; ++ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR) ++ attr = &__pthread_recursive_mutexattr; ++ ++ if (attr && attr->mutex_type == PTHREAD_MUTEX_ERRORCHECK) + { + + if (mutex->owner != _pthread_self ()) +@@ -46,7 +53,7 @@ __pthread_mutex_transfer_np (struct __pt + + #ifndef NDEBUG + # if !defined(ALWAYS_TRACK_MUTEX_OWNER) +- if (mutex->attr && mutex->attr->mutex_type != PTHREAD_MUTEX_NORMAL) ++ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL) + # endif + { + mutex->owner = thread; +--- a/libpthread/sysdeps/generic/pt-mutex-trylock.c ++++ b/libpthread/sysdeps/generic/pt-mutex-trylock.c +@@ -29,6 +29,12 @@ __pthread_mutex_trylock (struct __pthrea + { + int err; + struct __pthread *self; ++ const struct __pthread_mutexattr *attr = mutex->attr; ++ ++ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR) ++ attr = &__pthread_errorcheck_mutexattr; ++ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR) ++ attr = &__pthread_recursive_mutexattr; + + __pthread_spin_lock (&mutex->__lock); + if (__pthread_spin_trylock (&mutex->__held) == 0) +@@ -48,8 +54,8 @@ __pthread_mutex_trylock (struct __pthrea + #endif + #endif + +- if (mutex->attr) +- switch (mutex->attr->mutex_type) ++ if (attr) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_NORMAL: + break; +@@ -70,10 +76,10 @@ __pthread_mutex_trylock (struct __pthrea + + err = EBUSY; + +- if (mutex->attr) ++ if (attr) + { + self = _pthread_self (); +- switch (mutex->attr->mutex_type) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_NORMAL: + break; +--- a/libpthread/sysdeps/generic/pt-mutex-unlock.c ++++ b/libpthread/sysdeps/generic/pt-mutex-unlock.c +@@ -28,10 +28,16 @@ int + __pthread_mutex_unlock (pthread_mutex_t *mutex) + { + struct __pthread *wakeup; +- ++ const struct __pthread_mutexattr *attr = mutex->attr; ++ ++ if (attr == __PTHREAD_ERRORCHECK_MUTEXATTR) ++ attr = &__pthread_errorcheck_mutexattr; ++ if (attr == __PTHREAD_RECURSIVE_MUTEXATTR) ++ attr = &__pthread_recursive_mutexattr; ++ + __pthread_spin_lock (&mutex->__lock); + +- if (! mutex->attr || mutex->attr->mutex_type == PTHREAD_MUTEX_NORMAL) ++ if (! attr || attr->mutex_type == PTHREAD_MUTEX_NORMAL) + { + #if defined(ALWAYS_TRACK_MUTEX_OWNER) + # ifndef NDEBUG +@@ -45,7 +51,7 @@ __pthread_mutex_unlock (pthread_mutex_t + #endif + } + else +- switch (mutex->attr->mutex_type) ++ switch (attr->mutex_type) + { + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_RECURSIVE: +@@ -55,7 +61,7 @@ __pthread_mutex_unlock (pthread_mutex_t + return EPERM; + } + +- if (mutex->attr->mutex_type == PTHREAD_MUTEX_RECURSIVE) ++ if (attr->mutex_type == PTHREAD_MUTEX_RECURSIVE) + if (--mutex->locks > 0) + { + __pthread_spin_unlock (&mutex->__lock); +@@ -82,7 +88,7 @@ __pthread_mutex_unlock (pthread_mutex_t + + #ifndef NDEBUG + # if !defined (ALWAYS_TRACK_MUTEX_OWNER) +- if (mutex->attr && mutex->attr->mutex_type != PTHREAD_MUTEX_NORMAL) ++ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL) + # endif + { + mutex->owner = wakeup; +--- a/libpthread/sysdeps/generic/pt-mutexattr.c ++++ b/libpthread/sysdeps/generic/pt-mutexattr.c +@@ -28,6 +28,14 @@ const struct __pthread_mutexattr __pthre + mutex_type: PTHREAD_MUTEX_DEFAULT + }; + ++const struct __pthread_mutexattr __pthread_errorcheck_mutexattr = ++{ ++ prioceiling: 0, ++ protocol: PTHREAD_PRIO_NONE, ++ pshared: PTHREAD_PROCESS_PRIVATE, ++ mutex_type: PTHREAD_MUTEX_ERRORCHECK ++}; ++ + const struct __pthread_mutexattr __pthread_recursive_mutexattr = + { + prioceiling: 0, +--- a/libpthread/sysdeps/generic/bits/mutex.h ++++ b/libpthread/sysdeps/generic/bits/mutex.h +@@ -57,9 +57,17 @@ struct __pthread_mutex + # define __PTHREAD_MUTEX_INITIALIZER \ + { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, 0, 0, 0, 0 } + ++# define __PTHREAD_ERRORCHECK_MUTEXATTR ((struct __pthread_mutexattr *) ((unsigned long) __PTHREAD_MUTEX_ERRORCHECK + 1)) ++ ++# define __PTHREAD_ERRORCHECK_MUTEX_INITIALIZER \ ++ { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, \ ++ __PTHREAD_ERRORCHECK_MUTEXATTR, 0, 0, 0 } ++ ++# define __PTHREAD_RECURSIVE_MUTEXATTR ((struct __pthread_mutexattr *) ((unsigned long) __PTHREAD_MUTEX_RECURSIVE + 1)) ++ + # define __PTHREAD_RECURSIVE_MUTEX_INITIALIZER \ + { __PTHREAD_SPIN_LOCK_INITIALIZER, __PTHREAD_SPIN_LOCK_INITIALIZER, 0, 0, \ +- (struct __pthread_mutexattr *) &__pthread_recursive_mutexattr, 0, 0, 0 } ++ __PTHREAD_RECURSIVE_MUTEXATTR, 0, 0, 0 } + + # endif + #endif /* Not __pthread_mutex_defined. */ +--- a/libpthread/sysdeps/generic/bits/mutex-attr.h ++++ b/libpthread/sysdeps/generic/bits/mutex-attr.h +@@ -35,6 +35,7 @@ struct __pthread_mutexattr + }; + + /* Attributes for a recursive mutex. */ ++extern const struct __pthread_mutexattr __pthread_errorcheck_mutexattr; + extern const struct __pthread_mutexattr __pthread_recursive_mutexattr; + + #endif /* bits/mutex-attr.h */ diff --git a/debian/patches/libpthread_setcancel.patch b/debian/patches/libpthread_setcancel.patch new file mode 100644 index 00000000..601a698f --- /dev/null +++ b/debian/patches/libpthread_setcancel.patch @@ -0,0 +1,29 @@ +--- + libpthread/pthread/pt-setcancelstate.c | 3 ++- + libpthread/pthread/pt-setcanceltype.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +--- a/libpthread/pthread/pt-setcancelstate.c ++++ b/libpthread/pthread/pt-setcancelstate.c +@@ -35,7 +35,8 @@ pthread_setcancelstate (int state, int * + break; + } + +- *oldstate = p->cancel_state; ++ if (oldstate) ++ *oldstate = p->cancel_state; + p->cancel_state = state; + + return 0; +--- a/libpthread/pthread/pt-setcanceltype.c ++++ b/libpthread/pthread/pt-setcanceltype.c +@@ -35,7 +35,8 @@ pthread_setcanceltype (int type, int *ol + break; + } + +- *oldtype = p->cancel_type; ++ if (oldtype) ++ *oldtype = p->cancel_type; + p->cancel_type = type; + + return 0; diff --git a/debian/patches/libpthread_stubs.patch b/debian/patches/libpthread_stubs.patch new file mode 100644 index 00000000..f1937df0 --- /dev/null +++ b/debian/patches/libpthread_stubs.patch @@ -0,0 +1,156 @@ +--- + config.make.in | 1 + + libpthread/Makefile | 14 +++++++++++++- + libpthread/include/libc-symbols.h | 1 + + libpthread/sysdeps/generic/pt-atfork.c | 2 ++ + libpthread/sysdeps/generic/pt-getcpuclockid.c | 1 + + libpthread/sysdeps/generic/pt-getschedparam.c | 2 ++ + libpthread/sysdeps/generic/pt-key-create.c | 2 ++ + libpthread/sysdeps/generic/pt-key-delete.c | 2 ++ + libpthread/sysdeps/generic/pt-mutex-getprioceiling.c | 2 ++ + libpthread/sysdeps/generic/pt-mutex-setprioceiling.c | 2 ++ + libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c | 2 ++ + libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c | 2 ++ + libpthread/sysdeps/generic/pt-setschedparam.c | 2 ++ + libpthread/sysdeps/generic/pt-setschedprio.c | 2 ++ + 14 files changed, 36 insertions(+), 1 deletion(-) + +--- a/config.make.in ++++ b/config.make.in +@@ -44,6 +44,7 @@ RANLIB = @RANLIB@ + MIG = @MIG@ + MIGCOM = $(MIG) -cc cat - /dev/null + AWK = @AWK@ ++OBJDUMP = objdump + + # Compilation flags. Append these to the definitions already made by + # the specific Makefile. +--- a/libpthread/Makefile ++++ b/libpthread/Makefile +@@ -186,7 +186,7 @@ CPPFLAGS += \ + -imacros $(srcdir)/not-in-libc.h + + +-install: install-headers $(libdir)/libpthread2.a $(libdir)/libpthread2_pic.a ++install: install-headers $(libdir)/libpthread2.a $(libdir)/libpthread2_pic.a install-stubs-pthread + install-headers: $(addprefix $(includedir)/, $(sysdeps_headers)) + + # XXX: If $(libdir)/libpthread2.a is installed and +@@ -205,6 +205,18 @@ $(libdir)/libpthread2_pic.a: $(libdir)/l + mv $< $@ + $(INSTALL_DATA) $(srcdir)/libpthread_pic.a $< + ++install-stubs-pthread: stubs-pthread.h ++ mkdir -p $(includedir)/gnu ++ $(INSTALL_DATA) $< $(includedir)/gnu/stubs-pthread.h ++ ++stubs-pthread.h: $(OBJS) ++ $(OBJDUMP) -h $^ | \ ++ $(AWK) '/\.gnu\.glibc-stub\./ { \ ++ sub(/\.gnu\.glibc-stub\./, "", $$2); \ ++ stubs[$$2] = 1; } \ ++ END { for (s in stubs) print "#define __stub_" s }' > $@T ++ mv -f $@T $@ ++ + .PHONY: $(addprefix $(includedir)/, $(sysdeps_headers)) + + $(addprefix $(includedir)/, $(sysdeps_headers)): +--- a/libpthread/include/libc-symbols.h ++++ b/libpthread/include/libc-symbols.h +@@ -252,6 +252,7 @@ + + /* A canned warning for sysdeps/stub functions. */ + #define stub_warning(name) \ ++ __make_section_unallocated (".gnu.glibc-stub." #name) \ + link_warning (name, \ + "warning: " #name " is not implemented and will always fail") + +--- a/libpthread/sysdeps/generic/pt-atfork.c ++++ b/libpthread/sysdeps/generic/pt-atfork.c +@@ -27,3 +27,5 @@ pthread_atfork (void (*prepare) (void), + { + return ENOSYS; + } ++ ++stub_warning (pthread_atfork) +--- a/libpthread/sysdeps/generic/pt-getcpuclockid.c ++++ b/libpthread/sysdeps/generic/pt-getcpuclockid.c +@@ -30,5 +30,6 @@ pthread_getcpuclockid (pthread_t thread, + return 0; + #else + return ENOSYS; ++stub_warning (pthread_getcpuclockid) + #endif + } +--- a/libpthread/sysdeps/generic/pt-getschedparam.c ++++ b/libpthread/sysdeps/generic/pt-getschedparam.c +@@ -26,3 +26,5 @@ pthread_getschedparam (pthread_t thread, + { + return ENOSYS; + } ++ ++stub_warning (pthread_getschedparam) +--- a/libpthread/sysdeps/generic/pt-key-create.c ++++ b/libpthread/sysdeps/generic/pt-key-create.c +@@ -25,3 +25,5 @@ pthread_key_create (pthread_key_t *key, + { + return ENOSYS; + } ++ ++stub_warning (pthread_key_create) +--- a/libpthread/sysdeps/generic/pt-key-delete.c ++++ b/libpthread/sysdeps/generic/pt-key-delete.c +@@ -25,3 +25,5 @@ pthread_key_delete (pthread_key_t key) + { + return ENOSYS; + } ++ ++stub_warning (pthread_key_delete) +--- a/libpthread/sysdeps/generic/pt-mutex-getprioceiling.c ++++ b/libpthread/sysdeps/generic/pt-mutex-getprioceiling.c +@@ -26,3 +26,5 @@ pthread_mutex_getprioceiling (const pthr + { + return ENOSYS; + } ++ ++stub_warning (pthread_mutex_getprioceiling) +--- a/libpthread/sysdeps/generic/pt-mutex-setprioceiling.c ++++ b/libpthread/sysdeps/generic/pt-mutex-setprioceiling.c +@@ -26,3 +26,5 @@ pthread_mutex_setprioceiling (pthread_mu + { + return ENOSYS; + } ++ ++stub_warning (pthread_mutex_setprioceiling) +--- a/libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c ++++ b/libpthread/sysdeps/generic/pt-mutexattr-getprioceiling.c +@@ -26,3 +26,5 @@ pthread_mutexattr_getprioceiling (const + { + return ENOSYS; + } ++ ++stub_warning (pthread_mutexattr_getprioceiling) +--- a/libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c ++++ b/libpthread/sysdeps/generic/pt-mutexattr-setprioceiling.c +@@ -26,3 +26,5 @@ pthread_mutexattr_setprioceiling (pthrea + { + return ENOSYS; + } ++ ++stub_warning (pthread_mutexattr_setprioceiling) +--- a/libpthread/sysdeps/generic/pt-setschedparam.c ++++ b/libpthread/sysdeps/generic/pt-setschedparam.c +@@ -26,3 +26,5 @@ pthread_setschedparam (pthread_t thread, + { + return ENOSYS; + } ++ ++stub_warning (pthread_setschedparam) +--- a/libpthread/sysdeps/generic/pt-setschedprio.c ++++ b/libpthread/sysdeps/generic/pt-setschedprio.c +@@ -25,3 +25,5 @@ pthread_setschedprio (pthread_t thread, + { + return ENOSYS; + } ++ ++stub_warning (pthread_setschedprio) diff --git a/debian/patches/libpthread_tls.patch b/debian/patches/libpthread_tls.patch new file mode 100644 index 00000000..088ed8ee --- /dev/null +++ b/debian/patches/libpthread_tls.patch @@ -0,0 +1,329 @@ +--- + libpthread/pthread/pt-create.c | 7 ++++ + libpthread/pthread/pt-exit.c | 3 ++ + libpthread/pthread/pt-internal.h | 19 ++++++++++++ + libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c | 37 ++++++++++++++++++++++--- + libpthread/sysdeps/mach/hurd/ia32/pt-setup.c | 7 +++- + libpthread/sysdeps/mach/hurd/pt-docancel.c | 4 +- + libpthread/sysdeps/mach/hurd/pt-sysdep.h | 10 ++++-- + libthreads/alpha/thread.c | 1 + libthreads/cprocs.c | 3 +- + libthreads/cthread_internals.h | 16 ++++++++++ + libthreads/i386/thread.c | 32 +++++++++++++++++++-- + 11 files changed, 122 insertions(+), 17 deletions(-) + +--- a/libpthread/pthread/pt-create.c ++++ b/libpthread/pthread/pt-create.c +@@ -129,6 +129,11 @@ __pthread_create_internal (struct __pthr + if (err) + goto failed_thread_alloc; + ++ pthread->tcb = _dl_allocate_tls (NULL); ++ if (!pthread->tcb) ++ goto failed_thread_tls_alloc; ++ pthread->tcb->tcb = pthread->tcb; ++ + /* And initialize the rest of the machine context. This may include + additional machine- and system-specific initializations that + prove convenient. */ +@@ -194,6 +199,8 @@ __pthread_create_internal (struct __pthr + failed_sigstate: + __pthread_sigstate_destroy (pthread); + failed_setup: ++ _dl_deallocate_tls (pthread->tcb, 1); ++ failed_thread_tls_alloc: + __pthread_thread_dealloc (pthread); + __pthread_thread_halt (pthread); + failed_thread_alloc: +--- a/libpthread/pthread/pt-exit.c ++++ b/libpthread/pthread/pt-exit.c +@@ -70,6 +70,9 @@ pthread_exit (void *status) + if (self->cancel_state == PTHREAD_CANCEL_ENABLE && self->cancel_pending) + status = PTHREAD_CANCELED; + ++ if (self->tcb) ++ _dl_deallocate_tls (self->tcb, 1); ++ + switch (self->state) + { + default: +--- a/libpthread/pthread/pt-internal.h ++++ b/libpthread/pthread/pt-internal.h +@@ -54,6 +54,14 @@ enum pthread_state + # define PTHREAD_SYSDEP_MEMBERS + #endif + ++/* Type of the TCB. */ ++typedef struct ++{ ++ void *tcb; /* Points to this structure. */ ++ void *dtv; /* Vector of pointers to TLS data. */ ++ thread_t self; /* This thread's control port. */ ++} tcbhead_t; ++ + /* This structure describes a POSIX thread. */ + struct __pthread + { +@@ -89,6 +97,8 @@ struct __pthread + + PTHREAD_SYSDEP_MEMBERS + ++ tcbhead_t *tcb; ++ + struct __pthread *next, **prevp; + }; + +@@ -287,4 +297,13 @@ const struct __pthread_rwlockattr __pthr + /* Default condition attributes. */ + const struct __pthread_condattr __pthread_default_condattr; + ++ ++/* From glibc. */ ++ ++/* Dynamic linker TLS allocation. */ ++extern void *_dl_allocate_tls(void *); ++ ++/* Dynamic linker TLS deallocation. */ ++extern void _dl_deallocate_tls(void *, int); ++ + #endif /* pt-internal.h */ +--- a/libpthread/sysdeps/mach/hurd/pt-docancel.c ++++ b/libpthread/sysdeps/mach/hurd/pt-docancel.c +@@ -52,8 +52,8 @@ __pthread_do_cancel (struct __pthread *p + err = __thread_abort (p->kernel_thread); + assert_perror (err); + +- err = __thread_set_pcsp (p->kernel_thread, +- 1, (void *) call_exit, 0, 0); ++ err = __thread_set_pcsptp (p->kernel_thread, ++ 1, (void *) call_exit, 0, 0, 0, 0); + assert_perror (err); + + err = __thread_resume (p->kernel_thread); +--- a/libpthread/sysdeps/mach/hurd/pt-sysdep.h ++++ b/libpthread/sysdeps/mach/hurd/pt-sysdep.h +@@ -60,11 +60,13 @@ __pthread_stack_dealloc (void *stackaddr + __vm_deallocate (__mach_task_self (), (vm_offset_t) stackaddr, stacksize); + } + +-/* Change thread THREAD's program counter to PC if SET_PC is true and +- its stack pointer to SP if SET_IP is true. */ +-extern int __thread_set_pcsp (thread_t thread, ++/* Change thread THREAD's program counter to PC if SET_PC is true, ++ its stack pointer to SP if SET_IP is true, and its thread pointer ++ to TP if SET_TP is true. */ ++extern int __thread_set_pcsptp (thread_t thread, + int set_pc, void *pc, +- int set_sp, void *sp); ++ int set_sp, void *sp, ++ int set_tp, void *tp); + + + #endif /* pt-sysdep.h */ +--- a/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c ++++ b/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c +@@ -21,12 +21,28 @@ + + #include <mach.h> + #include <mach/i386/thread_status.h> ++#include <mach/i386/mach_i386.h> ++#include <mach/mig_errors.h> + #include <mach/thread_status.h> + ++#define HURD_TLS_DESC_DECL(desc, tcb) \ ++ struct descriptor desc = \ ++ { /* low word: */ \ ++ 0xffff /* limit 0..15 */ \ ++ | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \ ++ , /* high word: */ \ ++ ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \ ++ | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \ ++ | (0xf << 16) /* limit 16..19 */ \ ++ | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \ ++ | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \ ++ } ++ + int +-__thread_set_pcsp (thread_t thread, ++__thread_set_pcsptp (thread_t thread, + int set_ip, void *ip, +- int set_sp, void *sp) ++ int set_sp, void *sp, ++ int set_tp, void *tp) + { + error_t err; + struct i386_thread_state state; +@@ -34,7 +50,7 @@ __thread_set_pcsp (thread_t thread, + + state_count = i386_THREAD_STATE_COUNT; + +- err = __thread_get_state (thread, i386_THREAD_STATE, ++ err = __thread_get_state (thread, i386_REGS_SEGS_STATE, + (thread_state_t) &state, &state_count); + if (err) + return err; +@@ -43,8 +59,21 @@ __thread_set_pcsp (thread_t thread, + state.uesp = (unsigned int) sp; + if (set_ip) + state.eip = (unsigned int) ip; ++ if (set_tp) { ++ HURD_TLS_DESC_DECL(desc, tp); ++ int sel; ++ ++ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0)); ++ if (__builtin_expect (sel, 0x48) & 4) /* LDT selector */ ++ err = __i386_set_ldt (thread, sel, &desc, 1); ++ else ++ err = __i386_set_gdt (thread, &sel, desc); ++ if (err) ++ return err; ++ state.gs = sel; ++ } + +- err = __thread_set_state (thread, i386_THREAD_STATE, ++ err = __thread_set_state (thread, i386_REGS_SEGS_STATE, + (thread_state_t) &state, + i386_THREAD_STATE_COUNT); + if (err) +--- a/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c ++++ b/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c +@@ -91,12 +91,15 @@ __pthread_setup (struct __pthread *threa + thread->mcontext.pc = entry_point; + thread->mcontext.sp = stack_setup (thread, start_routine, arg); + ++ thread->tcb->self = thread->kernel_thread; ++ + ktid = __mach_thread_self (); + if (thread->kernel_thread != ktid) + { +- err = __thread_set_pcsp (thread->kernel_thread, ++ err = __thread_set_pcsptp (thread->kernel_thread, + 1, thread->mcontext.pc, +- 1, thread->mcontext.sp); ++ 1, thread->mcontext.sp, ++ 1, thread->tcb); + assert_perror (err); + } + __mach_port_deallocate (__mach_task_self (), ktid); +--- a/libthreads/cprocs.c ++++ b/libthreads/cprocs.c +@@ -730,10 +730,11 @@ cproc_create(void) + spin_lock(&n_kern_lock); + if (cthread_max_kernel_threads == 0 || + cthread_kernel_threads < cthread_max_kernel_threads) { ++ tcbhead_t *tcb = _dl_allocate_tls(NULL); + cthread_kernel_threads++; + spin_unlock(&n_kern_lock); + MACH_CALL(thread_create(mach_task_self(), &n), r); +- cproc_setup(child, n, cthread_body); /* machine dependent */ ++ cproc_setup(child, n, tcb, cthread_body); /* machine dependent */ + MACH_CALL(thread_resume(n), r); + #ifdef STATISTICS + spin_lock(&ready_lock); +--- a/libthreads/cthread_internals.h ++++ b/libthreads/cthread_internals.h +@@ -166,6 +166,14 @@ + # endif + #endif + ++/* Type of the TCB. */ ++typedef struct ++{ ++ void *tcb; /* Points to this structure. */ ++ void *dtv; /* Vector of pointers to TLS data. */ ++ thread_t self; /* This thread's control port. */ ++} tcbhead_t; ++ + /* + * Low-level thread implementation. + * This structure must agree with struct ur_cthread in cthreads.h +@@ -312,4 +320,10 @@ extern void cproc_prepare(cproc_t _chil + void (*cthread_body_pc)()); + + extern void cproc_setup(cproc_t _child, thread_t _mach_thread, +- void (*_routine)(cproc_t)); ++ tcbhead_t *tcb, void (*_routine)(cproc_t)); ++ ++ ++/* From glibc. */ ++ ++/* Dynamic linker TLS allocation. */ ++extern void *_dl_allocate_tls(void *); +--- a/libthreads/alpha/thread.c ++++ b/libthreads/alpha/thread.c +@@ -74,6 +74,7 @@ void + cproc_setup( + register cproc_t child, + thread_t thread, ++ tcbhead_t *tcb, /* TODO */ + void (*routine)(cproc_t)) + { + register integer_t *top; +--- a/libthreads/i386/thread.c ++++ b/libthreads/i386/thread.c +@@ -75,6 +75,21 @@ char rcs_id[] = "$Header: /cvsroot/hurd/ + #include <cthreads.h> + #include "cthread_internals.h" + #include <mach.h> ++#include <mach/i386/mach_i386.h> ++#include <mach/mig_errors.h> ++ ++#define HURD_TLS_DESC_DECL(desc, tcb) \ ++ struct descriptor desc = \ ++ { /* low word: */ \ ++ 0xffff /* limit 0..15 */ \ ++ | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \ ++ , /* high word: */ \ ++ ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \ ++ | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \ ++ | (0xf << 16) /* limit 16..19 */ \ ++ | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \ ++ | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \ ++ } + + /* + * Set up the initial state of a MACH thread +@@ -82,7 +97,7 @@ char rcs_id[] = "$Header: /cvsroot/hurd/ + * when it is resumed. + */ + void +-cproc_setup(register cproc_t child, thread_t thread, void (*routine)(cproc_t)) ++cproc_setup(register cproc_t child, thread_t thread, tcbhead_t *tcb, void (*routine)(cproc_t)) + { + extern unsigned int __hurd_threadvar_max; /* GNU */ + register int *top = (int *) +@@ -95,13 +110,15 @@ cproc_setup(register cproc_t child, thre + register struct i386_thread_state *ts = &state; + kern_return_t r; + unsigned int count; ++ HURD_TLS_DESC_DECL(desc, tcb); ++ int sel; + + /* + * Set up i386 call frame and registers. + * Read registers first to get correct segment values. + */ + count = i386_THREAD_STATE_COUNT; +- MACH_CALL(thread_get_state(thread,i386_THREAD_STATE,(thread_state_t) &state,&count),r); ++ MACH_CALL(thread_get_state(thread,i386_REGS_SEGS_STATE,(thread_state_t) &state,&count),r); + + ts->eip = (int) routine; + *--top = (int) child; /* argument to function */ +@@ -109,7 +126,16 @@ cproc_setup(register cproc_t child, thre + ts->uesp = (int) top; /* set stack pointer */ + ts->ebp = 0; /* clear frame pointer */ + +- MACH_CALL(thread_set_state(thread,i386_THREAD_STATE,(thread_state_t) &state,i386_THREAD_STATE_COUNT),r); ++ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0)); ++ tcb->tcb = tcb; ++ tcb->self = thread; ++ if (__builtin_expect (sel, 0x48) & 4) /* LDT selector */ ++ __i386_set_ldt (thread, sel, &desc, 1); ++ else ++ __i386_set_gdt (thread, &sel, desc); ++ ts->gs = sel; ++ ++ MACH_CALL(thread_set_state(thread,i386_REGS_SEGS_STATE,(thread_state_t) &state,i386_THREAD_STATE_COUNT),r); + } + + #if defined(cthread_sp) diff --git a/debian/patches/makedev.diff b/debian/patches/makedev.diff new file mode 100644 index 00000000..f53320c5 --- /dev/null +++ b/debian/patches/makedev.diff @@ -0,0 +1,17 @@ +Do not create the shm node since Marcus' SHM implementation uses a directory +there. +--- + sutils/MAKEDEV.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sutils/MAKEDEV.sh ++++ b/sutils/MAKEDEV.sh +@@ -86,7 +86,7 @@ function mkdev { + ;; + + std) +- mkdev console tty null zero full fd time mem klog shm ++ mkdev console tty null zero full fd time mem klog + ;; + console|com[0-9]) + st $I root 600 /hurd/term ${DEVDIR}/$I device $I;; diff --git a/debian/patches/pfinet-gcc-4.3-fix.patch b/debian/patches/pfinet-gcc-4.3-fix.patch new file mode 100644 index 00000000..fbc31da9 --- /dev/null +++ b/debian/patches/pfinet-gcc-4.3-fix.patch @@ -0,0 +1,36 @@ +commit acb9f2e4bc53e0483e53549379c9c5631e452334 +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Sat Sep 26 21:29:00 2009 +0200 + + Add memory clobbers to assembly snippets + + * pfinet/linux-src/include/asm-i386/checksum.h (ip_fast_csum): + Add memory clobber to assembly snippet. + (csum_ipv6_magic): Likewise. + +--- + pfinet/linux-src/include/asm-i386/checksum.h | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/pfinet/linux-src/include/asm-i386/checksum.h ++++ b/pfinet/linux-src/include/asm-i386/checksum.h +@@ -109,7 +109,8 @@ static inline unsigned short ip_fast_csu + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl) +- : "1" (iph), "2" (ihl)); ++ : "1" (iph), "2" (ihl) ++ : "memory"); + return(sum); + } + +@@ -185,7 +186,8 @@ static __inline__ unsigned short int csu + "adcl $0, %0\n" + : "=&r" (sum) + : "r" (saddr), "r" (daddr), +- "r"(htonl((__u32) (len))), "r"(htonl(proto)), "0"(sum)); ++ "r"(htonl((__u32) (len))), "r"(htonl(proto)), "0"(sum) ++ : "memory"); + + return csum_fold(sum); + } diff --git a/debian/patches/pfinet_dhcp.patch b/debian/patches/pfinet_dhcp.patch new file mode 100644 index 00000000..30c0902a --- /dev/null +++ b/debian/patches/pfinet_dhcp.patch @@ -0,0 +1,560 @@ +2007-10-14 Christian Dietrich <stettberger@dokucode.de> + + * options.c (options): Marked -a, -g -m, -p, -A, -G + OPTION_ARG_OPTIONAL. Adding -d option. + (parse_interface_copy_device): New function. + (parse_opt): When selecting another interface with -i + set the options from e.g. a prior fsysopts call as default + values. For -a, -g, -p, -g, -A, -G set the optional + argument as value. When there is no argument, delete the + value (e.g. unset default gateway). Delete delete default gateways + only if the set gateway is on an interface modified in this call. + Add always an route for dhcp packages on all devices. By doing + this we can send dhcp renew packages. + (trivfs_append_args): Add --gateway only once. + +2007-10-14 Marco Gerards <metgerards@student.han.nl> + + * options.c (options): Add the option `dhcp'. + (parse_hook_add_interface): Initialize the `dhcp' member for the + parse hook. + (parse_opt): In case pfinet is started with the argument `--dhcp', + set the address to `0.0.0.0', the netmask to `255.0.0.0' and add + the route for `0.0.0.0' so broadcasting works. + + * linux-src/net/ipv4/devinet.c (inet_insert_ifa) [_HURD_]: Don't + fail when the address is `0.0.0.0'. + +--- + pfinet/linux-src/net/ipv4/devinet.c | 2 + pfinet/options.c | 381 ++++++++++++++++++++++++++---------- + 2 files changed, 278 insertions(+), 105 deletions(-) + +--- a/pfinet/options.c ++++ b/pfinet/options.c +@@ -60,23 +60,26 @@ extern struct inet6_dev *ipv6_find_idev + extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen); + extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen); + ++#ifdef CONFIG_IPV6 ++static struct rt6_info * ipv6_get_dflt_router (void); ++#endif ++ + + /* Pfinet options. Used for both startup and runtime. */ + static const struct argp_option options[] = + { +- {"interface", 'i', "DEVICE", 0, "Network interface to use", 1}, ++ {"interface", 'i', "DEVICE", 0, "Network interface to use", 1}, + {0,0,0,0,"These apply to a given interface:", 2}, +- {"address", 'a', "ADDRESS", 0, "Set the network address"}, +- {"netmask", 'm', "MASK", 0, "Set the netmask"}, +- {"peer", 'p', "ADDRESS", 0, "Set the peer address"}, +- {"gateway", 'g', "ADDRESS", 0, "Set the default gateway"}, +- {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"}, ++ {"address", 'a', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the network address"}, ++ {"netmask", 'm', "MASK", OPTION_ARG_OPTIONAL, "Set the netmask"}, ++ {"peer", 'p', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the peer address"}, ++ {"gateway", 'g', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the default gateway"}, ++ {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"}, + #ifdef CONFIG_IPV6 +- {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"}, +- {"address6", 'A', "ADDR/LEN",0, "Set the global IPv6 address"}, +- {"gateway6", 'G', "ADDRESS", 0, "Set the IPv6 default gateway"}, ++ {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"}, ++ {"address6", 'A', "ADDR/LEN", OPTION_ARG_OPTIONAL, "Set the global IPv6 address"}, ++ {"gateway6", 'G', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the IPv6 default gateway"}, + #endif +- {"shutdown", 's', 0, 0, "Shut it down"}, + {0} + }; + +@@ -112,6 +115,50 @@ struct parse_hook + struct parse_interface *curint; + }; + ++static void ++parse_interface_copy_device(struct device *src, ++ struct parse_interface *dst) ++{ ++ uint32_t broad; ++ struct rt_key key = { 0 }; ++ struct inet6_dev *idev = NULL; ++ struct fib_result res; ++ ++ inquire_device (src, &dst->address, &dst->netmask, ++ &dst->peer, &broad); ++ /* Get gateway */ ++ dst->gateway = INADDR_NONE; ++ key.oif = src->ifindex; ++ if (! main_table->tb_lookup (main_table, &key, &res) ++ && FIB_RES_GW(res) != INADDR_ANY) ++ dst->gateway = FIB_RES_GW (res); ++#ifdef CONFIG_IPV6 ++ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL) ++ idev = ipv6_find_idev(src); ++ ++ if (idev) ++ { ++ struct inet6_ifaddr *ifa = idev->addr_list; ++ ++ /* Look for IPv6 default router and add it to the interface, ++ * if it belongs to it. ++ */ ++ struct rt6_info *rt6i = ipv6_get_dflt_router(); ++ if (rt6i->rt6i_dev == src) ++ memcpy (&dst->gateway6, &rt6i->rt6i_gateway, sizeof (struct in6_addr)); ++ /* Search for global address and set it in dst */ ++ do ++ { ++ if (!IN6_IS_ADDR_LINKLOCAL (&ifa->addr)) { ++ memcpy (&dst->address6, ifa, sizeof (struct inet6_ifaddr)); ++ break; ++ } ++ } ++ while ((ifa = ifa->if_next)); ++ } ++#endif ++} ++ + /* Adds an empty interface slot to H, and sets H's current interface to it, or + returns an error. */ + static error_t +@@ -122,6 +169,7 @@ parse_hook_add_interface (struct parse_h + (h->num_interfaces + 1) * sizeof (struct parse_interface)); + if (! new) + return ENOMEM; ++ + h->interfaces = new; + h->num_interfaces++; + h->curint = new + h->num_interfaces - 1; +@@ -183,10 +231,16 @@ parse_opt (int opt, char *arg, struct ar + if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \ + addr; }) + ++ if (!arg && state->next < state->argc ++ && (*state->argv[state->next] != '-')) ++ { ++ arg = state->argv[state->next]; ++ state->next ++; ++ } ++ + switch (opt) + { +- struct parse_interface *in; +- uint32_t gateway; ++ struct parse_interface *in, *gw4_in; + #ifdef CONFIG_IPV6 + struct parse_interface *gw6_in; + char *ptr; +@@ -217,29 +271,59 @@ parse_opt (int opt, char *arg, struct ar + if (err) + FAIL (err, 10, err, "%s", arg); + ++ /* Set old interface values */ ++ parse_interface_copy_device (in->device, in); + break; + + case 'a': +- h->curint->address = ADDR (arg, "address"); +- if (!IN_CLASSA (ntohl (h->curint->address)) +- && !IN_CLASSB (ntohl (h->curint->address)) +- && !IN_CLASSC (ntohl (h->curint->address))) +- { +- if (IN_MULTICAST (ntohl (h->curint->address))) +- FAIL (EINVAL, 1, 0, +- "%s: Cannot set interface address to multicast address", +- arg); +- else +- FAIL (EINVAL, 1, 0, +- "%s: Illegal or undefined network address", arg); +- } ++ if (arg) ++ { ++ h->curint->address = ADDR (arg, "address"); ++ if (!IN_CLASSA (ntohl (h->curint->address)) ++ && !IN_CLASSB (ntohl (h->curint->address)) ++ && !IN_CLASSC (ntohl (h->curint->address))) ++ { ++ if (IN_MULTICAST (ntohl (h->curint->address))) ++ FAIL (EINVAL, 1, 0, ++ "%s: Cannot set interface address to multicast address", ++ arg); ++ else ++ FAIL (EINVAL, 1, 0, ++ "%s: Illegal or undefined network address", arg); ++ } ++ } else { ++ h->curint->address = ADDR ("0.0.0.0", "address"); ++ h->curint->netmask = ADDR ("255.0.0.0", "netmask"); ++ h->curint->gateway = INADDR_NONE; ++ } + break; ++ + case 'm': +- h->curint->netmask = ADDR (arg, "netmask"); break; ++ if (arg) ++ h->curint->netmask = ADDR (arg, "netmask"); ++ else ++ h->curint->netmask = INADDR_NONE; ++ break; ++ + case 'p': +- h->curint->peer = ADDR (arg, "peer"); break; ++ if (arg) ++ h->curint->peer = ADDR (arg, "peer"); ++ else ++ h->curint->peer = INADDR_NONE; ++ break; ++ + case 'g': +- h->curint->gateway = ADDR (arg, "gateway"); break; ++ if (arg) ++ { ++ /* Remove an possible other default gateway */ ++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; ++ in++) ++ in->gateway = INADDR_NONE; ++ h->curint->gateway = ADDR (arg, "gateway"); ++ } ++ else ++ h->curint->gateway = INADDR_NONE; ++ break; + + case '4': + pfinet_bind (PORTCLASS_INET, arg); +@@ -254,36 +338,46 @@ parse_opt (int opt, char *arg, struct ar + break; + + case 'A': +- if ((ptr = strchr (arg, '/'))) ++ if (arg) + { +- h->curint->address6.prefix_len = atoi (ptr + 1); +- if (h->curint->address6.prefix_len > 128) +- FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg); ++ if ((ptr = strchr (arg, '/'))) ++ { ++ h->curint->address6.prefix_len = atoi (ptr + 1); ++ if (h->curint->address6.prefix_len > 128) ++ FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg); ++ ++ *ptr = 0; ++ } ++ else ++ { ++ h->curint->address6.prefix_len = 64; ++ fprintf (stderr, "No prefix-length given, " ++ "defaulting to %s/64.\n", arg); ++ } + +- *ptr = 0; ++ if (inet_pton (AF_INET6, arg, &h->curint->address6.addr) <= 0) ++ PERR (EINVAL, "Malformed address"); ++ ++ if (IN6_IS_ADDR_MULTICAST (&h->curint->address6.addr)) ++ FAIL (EINVAL, 1, 0, "%s: Cannot set interface address to " ++ "multicast address", arg); + } + else +- { +- h->curint->address6.prefix_len = 64; +- fprintf (stderr, "No prefix-length given, defaulting to %s/64.\n", +- arg); +- } +- +- if (inet_pton (AF_INET6, arg, &h->curint->address6.addr) <= 0) +- PERR (EINVAL, "Malformed address"); +- +- if (IN6_IS_ADDR_MULTICAST (&h->curint->address6.addr)) +- FAIL (EINVAL, 1, 0, "%s: Cannot set interface address to " +- "multicast address", arg); ++ memset (&h->curint->address6, 0, sizeof (struct inet6_ifaddr)); + break; + + case 'G': +- if (inet_pton (AF_INET6, arg, &h->curint->gateway6) <= 0) +- PERR (EINVAL, "Malformed gateway"); ++ if (arg) ++ { ++ if (inet_pton (AF_INET6, arg, &h->curint->gateway6) <= 0) ++ PERR (EINVAL, "Malformed gateway"); + +- if (IN6_IS_ADDR_MULTICAST (&h->curint->gateway6)) +- FAIL (EINVAL, 1, 0, "%s: Cannot set gateway to " +- "multicast address", arg); ++ if (IN6_IS_ADDR_MULTICAST (&h->curint->gateway6)) ++ FAIL (EINVAL, 1, 0, "%s: Cannot set gateway to " ++ "multicast address", arg); ++ } ++ else ++ memset (&h->curint->gateway6, 0, sizeof (struct in6_addr)); + break; + #endif /* CONFIG_IPV6 */ + +@@ -323,20 +417,19 @@ parse_opt (int opt, char *arg, struct ar + /* Specifying a netmask for an address-less interface is a no-no. */ + FAIL (EDESTADDRREQ, 14, 0, "Cannot set netmask"); + #endif +- +- gateway = INADDR_NONE; + #ifdef CONFIG_IPV6 + gw6_in = NULL; + #endif ++ gw4_in = NULL; + for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) + { ++ /* delete interface if it doesn't match the actual netmask */ ++ if (! ( (h->curint->address & h->curint->netmask) ++ == (h->curint->gateway & h->curint->netmask))) ++ h->curint->gateway = INADDR_NONE; ++ + if (in->gateway != INADDR_NONE) +- { +- if (gateway != INADDR_NONE) +- FAIL (err, 15, 0, "Cannot have multiple default gateways"); +- gateway = in->gateway; +- in->gateway = INADDR_NONE; +- } ++ gw4_in = in; + + #ifdef CONFIG_IPV6 + if (!IN6_IS_ADDR_UNSPECIFIED (&in->gateway6)) +@@ -361,15 +454,20 @@ parse_opt (int opt, char *arg, struct ar + idev = ipv6_find_idev(in->device); + #endif + +- if (in->address != INADDR_NONE || in->netmask != INADDR_NONE) ++ if (in->address == INADDR_NONE && in->netmask == INADDR_NONE) ++ { ++ h->curint->address = ADDR ("0.0.0.0", "address"); ++ h->curint->netmask = ADDR ("255.0.0.0", "netmask"); ++ } ++ ++ if (in->device) ++ err = configure_device (in->device, in->address, in->netmask, ++ in->peer, INADDR_NONE); ++ ++ if (err) + { +- err = configure_device (in->device, in->address, in->netmask, +- in->peer, INADDR_NONE); +- if (err) +- { +- __mutex_unlock (&global_lock); +- FAIL (err, 16, 0, "cannot configure interface"); +- } ++ __mutex_unlock (&global_lock); ++ FAIL (err, 16, 0, "cannot configure interface"); + } + + #ifdef CONFIG_IPV6 +@@ -377,24 +475,25 @@ parse_opt (int opt, char *arg, struct ar + continue; + + /* First let's remove all non-local addresses. */ +- struct inet6_ifaddr *ifa = idev->addr_list; +- +- while (ifa) +- { +- struct inet6_ifaddr *c_ifa = ifa; +- ifa = ifa->if_next; +- +- if (IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr)) +- memset (&in->address6, 0, sizeof (struct inet6_ifaddr)); +- +- else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr) +- && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr)) +- inet6_addr_del (in->device->ifindex, &c_ifa->addr, +- c_ifa->prefix_len); +- } +- +- if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr)) +- { ++ struct inet6_ifaddr *ifa = idev->addr_list; ++ ++ while (ifa) ++ { ++ struct inet6_ifaddr *c_ifa = ifa; ++ ifa = ifa->if_next; ++ ++ if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr) ++ && IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr)) ++ memset (&in->address6, 0, sizeof (struct inet6_ifaddr)); ++ ++ else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr) ++ && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr)) ++ inet6_addr_del (in->device->ifindex, &c_ifa->addr, ++ c_ifa->prefix_len); ++ } ++ ++ if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr)) ++ { + /* Now assign the new address */ + inet6_addr_add (in->device->ifindex, &in->address6.addr, + in->address6.prefix_len); +@@ -418,33 +517,40 @@ parse_opt (int opt, char *arg, struct ar + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); + +- bzero (&req.rtm, sizeof req.rtm); +- bzero (&rta, sizeof rta); ++ memset (&req.rtm, 0, sizeof req.rtm); ++ memset (&rta, 0, sizeof rta); + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_protocol = RTPROT_STATIC; +- rta.rta_gw = &gateway; + +- if (gateway == INADDR_NONE) ++ if (!gw4_in) + { +- /* Delete any existing default route. */ +- req.nlh.nlmsg_type = RTM_DELROUTE; +- req.nlh.nlmsg_flags = 0; +- tb = fib_get_table (req.rtm.rtm_table); +- if (tb) +- { +- err = - (*tb->tb_delete) (tb, &req.rtm, &rta, &req.nlh, 0); +- if (err && err != ESRCH) +- { +- __mutex_unlock (&global_lock); +- FAIL (err, 17, 0, "cannot remove old default gateway"); +- } +- err = 0; +- } ++ /* Delete any existing default route on configured devices */ ++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; ++ in++) { ++ req.nlh.nlmsg_type = RTM_DELROUTE; ++ req.nlh.nlmsg_flags = 0; ++ rta.rta_oif = &in->device->ifindex; ++ tb = fib_get_table (req.rtm.rtm_table); ++ if (tb) ++ { ++ err = - (*tb->tb_delete) ++ (tb, &req.rtm, &rta, &req.nlh, 0); ++ if (err && err != ESRCH) ++ { ++ __mutex_unlock (&global_lock); ++ FAIL (err, 17, 0, ++ "cannot remove old default gateway"); ++ } ++ err = 0; ++ } ++ } + } + else + { + /* Add a default route, replacing any existing one. */ ++ rta.rta_oif = &gw4_in->device->ifindex; ++ rta.rta_gw = &gw4_in->gateway; + req.nlh.nlmsg_type = RTM_NEWROUTE; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; + tb = fib_new_table (req.rtm.rtm_table); +@@ -467,13 +573,77 @@ parse_opt (int opt, char *arg, struct ar + if (!gw6_in || rt6i->rt6i_dev != gw6_in->device + || !IN6_ARE_ADDR_EQUAL (&rt6i->rt6i_gateway, &gw6_in->gateway6)) + { +- rt6_purge_dflt_routers (0); ++ /* Delete any existing default route on configured devices */ ++ for (in = h->interfaces; in < h->interfaces ++ + h->num_interfaces; in++) ++ if (rt6i->rt6i_dev == in->device || gw6_in ) ++ rt6_purge_dflt_routers (0); ++ + if (gw6_in) + rt6_add_dflt_router (&gw6_in->gateway6, gw6_in->device); + } + } + #endif + ++ /* Setup the routing required for DHCP. */ ++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) ++ { ++ struct kern_rta rta; ++ struct ++ { ++ struct nlmsghdr nlh; ++ struct rtmsg rtm; ++ } req; ++ struct fib_table *tb; ++ struct rtentry route; ++ struct sockaddr_in *dst; ++ struct device *dev; ++ ++ if (!in->device) ++ continue; ++ ++ dst = (struct sockaddr_in *) &route.rt_dst; ++ if (!in->device->name) ++ { ++ __mutex_unlock (&global_lock); ++ FAIL (ENODEV, 17, 0, "unknown device"); ++ } ++ dev = dev_get (in->device->name); ++ if (!dev) ++ { ++ __mutex_unlock (&global_lock); ++ FAIL (ENODEV, 17, 0, "unknown device"); ++ } ++ ++ /* Simulate the SIOCADDRT behavior. */ ++ memset (&route, 0, sizeof (struct rtentry)); ++ memset (&req.rtm, 0, sizeof req.rtm); ++ memset (&rta, 0, sizeof rta); ++ req.nlh.nlmsg_type = RTM_NEWROUTE; ++ ++ /* Append this routing for 0.0.0.0. By this way we can send always ++ dhcp messages (e.g dhcp renew). */ ++ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE ++ | NLM_F_APPEND; ++ req.rtm.rtm_protocol = RTPROT_BOOT; ++ req.rtm.rtm_scope = RT_SCOPE_LINK; ++ req.rtm.rtm_type = RTN_UNICAST; ++ rta.rta_dst = &dst->sin_addr.s_addr; ++ rta.rta_oif = &dev->ifindex; ++ ++ tb = fib_new_table (req.rtm.rtm_table); ++ if (tb) ++ err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); ++ else ++ err = ENOBUFS; ++ ++ if (err) ++ { ++ __mutex_unlock (&global_lock); ++ FAIL (err, 17, 0, "cannot add route"); ++ } ++ } ++ + __mutex_unlock (&global_lock); + + /* Fall through to free hook. */ +@@ -526,8 +696,9 @@ trivfs_append_args (struct trivfs_contro + ADD_ADDR_OPT ("netmask", mask); + if (peer != addr) + ADD_ADDR_OPT ("peer", peer); +- key.iif = dev->ifindex; +- if (! main_table->tb_lookup (main_table, &key, &res)) ++ key.oif = dev->ifindex; ++ if (! main_table->tb_lookup (main_table, &key, &res) ++ && FIB_RES_GW(res) != INADDR_ANY) + ADD_ADDR_OPT ("gateway", FIB_RES_GW (res)); + + #undef ADD_ADDR_OPT +--- a/pfinet/linux-src/net/ipv4/devinet.c ++++ b/pfinet/linux-src/net/ipv4/devinet.c +@@ -214,10 +214,12 @@ inet_insert_ifa(struct in_device *in_dev + { + struct in_ifaddr *ifa1, **ifap, **last_primary; + ++#ifndef _HURD_ + if (ifa->ifa_local == 0) { + inet_free_ifa(ifa); + return 0; + } ++#endif + + ifa->ifa_flags &= ~IFA_F_SECONDARY; + last_primary = &in_dev->ifa_list; diff --git a/debian/patches/pflocal.patch b/debian/patches/pflocal.patch new file mode 100644 index 00000000..3d9b3ac2 --- /dev/null +++ b/debian/patches/pflocal.patch @@ -0,0 +1,674 @@ +2005-05-17 Neal H. Walfield <neal@gnu.org> + + * connq.h (struct connq_request): Remove forward. + (connq_listen): Wait for a request to be queued not until there is + a connection attempt. Remove REQ parameter. Update callers. + (connq_request_complete): Remove declaration. + (connq_connect): Wait for a slot to queue a request not until + there is an acceptor. Remove SOCK parameter. Update callers. + (connq_connect_complete): New declaration. + (connq_connect_cancel): New declaration. + + * connq.c (struct connq): Remove fields noqueue, queue, length, + head and tail. Add fields head, tail, count, max, connectors and + num_connectors. That is, replace the circular buffer with a + singly linked list. + (qnext): Remove function. + (struct connq_request): Remove field signal, lock, completed and + err. Add field next. + (connq_request_init): Rewrite according to new semantics. + (connq_request_enqueue): New function. + (connq_request_dequeue): New function. + (connq_create): Update according to new semantics. + (connq_destroy): Likewise. + (connq_listen): Rewrite to not block until there is a connector + but until there is a request in the queue. + (connq_request_complete): Remove function. + (connq_connect): Rewrite to not block until there is an acceptor + but until there is space for a request. + (connq_connect_complete): New function. + (connq_connect_cancel): New function. + (connq_compress): Remove dead code. + (connq_set_length): Rewrite. + + * socket.c (S_socket_connect): Create the server socket here... + (S_socket_accept): ... not here. + +--- + pflocal/connq.c | 341 +++++++++++++++++++++++++++++-------------------------- + pflocal/connq.h | 39 +++--- + pflocal/io.c | 8 - + pflocal/socket.c | 72 +++++------ + 4 files changed, 245 insertions(+), 215 deletions(-) + +--- a/pflocal/connq.c ++++ b/pflocal/connq.c +@@ -26,31 +26,22 @@ + /* A queue for queueing incoming connections. */ + struct connq + { +- /* True if all connection requests should be treated as non-blocking. */ +- int noqueue; +- + /* The connection request queue. */ +- struct connq_request **queue; +- unsigned length; +- /* Head is the position in QUEUE of the first request, and TAIL is the +- first free position in the queue. If HEAD == TAIL, then the queue is +- empty. Starting at HEAD, successive positions can be calculated by +- using qnext(). */ +- unsigned head, tail; ++ struct connq_request *head; ++ struct connq_request **tail; ++ unsigned count; ++ unsigned max; + + /* Threads that have done an accept on this queue wait on this condition. */ + struct condition listeners; + unsigned num_listeners; + ++ /* Threads that have done a connect on this queue wait on this condition. */ ++ struct condition connectors; ++ unsigned num_connectors; ++ + struct mutex lock; + }; +- +-/* Returns the position CQ's queue after POS. */ +-static inline unsigned +-qnext (struct connq *cq, unsigned pos) +-{ +- return (pos + 1 == cq->length) ? 0 : pos + 1; +-} + + /* ---------------------------------------------------------------- */ + +@@ -58,30 +49,50 @@ qnext (struct connq *cq, unsigned pos) + get information from and to the thread. */ + struct connq_request + { ++ struct connq_request *next; ++ + /* The socket that's waiting to connect. */ + struct sock *sock; +- +- /* What the waiting thread blocks on. */ +- struct condition signal; +- struct mutex lock; +- +- /* Set to true when this request has been dealt with, to guard against +- spurious conditions being signaled. */ +- int completed; +- +- /* After the waiting thread is unblocked, this is the result, either 0 if +- SOCK has been connected, or an error. */ +- error_t err; + }; + + static inline void + connq_request_init (struct connq_request *req, struct sock *sock) + { +- req->err = 0; + req->sock = sock; +- req->completed = 0; +- condition_init (&req->signal); +- mutex_init (&req->lock); ++} ++ ++/* Enqueue connection request REQ onto CQ. CQ must be locked. */ ++static void ++connq_request_enqueue (struct connq *cq, struct connq_request *req) ++{ ++ assert (! mutex_try_lock (&cq->lock)); ++ ++ req->next = NULL; ++ *cq->tail = req; ++ cq->tail = &req->next; ++ ++ cq->count ++; ++} ++ ++/* Dequeue a pending request from CQ. CQ must be locked and must not ++ be empty. */ ++static struct connq_request * ++connq_request_dequeue (struct connq *cq) ++{ ++ struct connq_request *req; ++ ++ assert (! mutex_try_lock (&cq->lock)); ++ assert (cq->head); ++ ++ req = cq->head; ++ cq->head = req->next; ++ if (! cq->head) ++ /* We just dequeued the last element. Fixup the tail pointer. */ ++ cq->tail = &cq->head; ++ ++ cq->count --; ++ ++ return req; + } + + /* ---------------------------------------------------------------- */ +@@ -95,16 +106,20 @@ connq_create (struct connq **cq) + struct connq *new = malloc (sizeof (struct connq)); + + if (!new) +- return ENOMEM; ++ return ENOBUFS; ++ ++ new->head = NULL; ++ new->tail = &new->head; ++ new->count = 0; ++ /* By default, don't queue requests. */ ++ new->max = 0; + +- new->noqueue = 1; /* By default, don't queue requests. */ +- new->length = 0; +- new->head = new->tail = 0; +- new->queue = NULL; + new->num_listeners = 0; ++ new->num_connectors = 0; + + mutex_init (&new->lock); + condition_init (&new->listeners); ++ condition_init (&new->connectors); + + *cq = new; + return 0; +@@ -116,175 +131,189 @@ connq_destroy (struct connq *cq) + { + /* Everybody in the queue should hold a reference to the socket + containing the queue. */ +- assert (cq->length == 0); +- /* Nevertheless, malloc(0) or realloc(0) might allocate some small +- space. */ +- if (cq->queue) +- free (cq->queue); ++ assert (! cq->head); ++ assert (cq->count == 0); ++ + free (cq); + } + + /* ---------------------------------------------------------------- */ + +-/* Wait for a connection attempt to be made on CQ, and return the connecting +- socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is +- left in the queue, otherwise connq_request_complete must be called on REQ +- to allow the requesting thread to continue. If NOBLOCK is true, +- EWOULDBLOCK is returned when there are no immediate connections +- available. */ ++/* Return a connection request on CQ. If SOCK is NULL, the request is ++ left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned ++ when there are no immediate connections available. */ + error_t +-connq_listen (struct connq *cq, int noblock, +- struct connq_request **req, struct sock **sock) ++connq_listen (struct connq *cq, int noblock, struct sock **sock) + { ++ error_t err = 0; ++ + mutex_lock (&cq->lock); + +- if (noblock && cq->head == cq->tail) ++ if (noblock && cq->count == 0 && cq->num_connectors == 0) + { + mutex_unlock (&cq->lock); + return EWOULDBLOCK; + } + ++ if (! sock && (cq->count > 0 || cq->num_connectors > 0)) ++ /* The caller just wants to know if a connection ready. */ ++ { ++ mutex_unlock (&cq->lock); ++ return 0; ++ } ++ + cq->num_listeners++; + +- while (cq->head == cq->tail) +- if (hurd_condition_wait (&cq->listeners, &cq->lock)) +- { +- cq->num_listeners--; +- mutex_unlock (&cq->lock); +- return EINTR; +- } ++ if (cq->count == 0) ++ /* The request queue is empty. */ ++ { ++ assert (! cq->head); ++ ++ if (cq->num_connectors > 0) ++ /* Someone is waiting for an acceptor. Signal that we can ++ service their request. */ ++ condition_signal (&cq->connectors); ++ ++ do ++ if (hurd_condition_wait (&cq->listeners, &cq->lock)) ++ { ++ cq->num_listeners--; ++ err = EINTR; ++ goto out; ++ } ++ while (cq->count == 0); ++ } ++ ++ assert (cq->head); + +- if (req != NULL) ++ if (sock) + /* Dequeue the next request, if desired. */ + { +- *req = cq->queue[cq->head]; +- cq->head = qnext (cq, cq->head); +- if (sock != NULL) +- *sock = (*req)->sock; ++ struct connq_request *req = connq_request_dequeue (cq); ++ *sock = req->sock; ++ free (req); + } ++ else if (cq->num_listeners > 0) ++ /* The caller will not actually process this request but someone ++ else could. (This case is rare but possible: it would require ++ one thread to do a select on the socket and a second to do an ++ accept.) */ ++ condition_signal (&cq->listeners); ++ else ++ /* There is no one else to process the request and the connection ++ has now been initiated. This is not actually a problem as even ++ if the current queue limit is 0, the connector will queue the ++ request and another listener (should) eventually come along. ++ (In fact it is very probably as the caller has likely done a ++ select and will now follow up with an accept.) */ ++ ; + +- cq->num_listeners--; +- ++ out: + mutex_unlock (&cq->lock); +- +- return 0; +-} +- +-/* Return the error code ERR to the thread that made the listen request REQ, +- returned from a previous connq_listen. */ +-void +-connq_request_complete (struct connq_request *req, error_t err) +-{ +- mutex_lock (&req->lock); +- req->err = err; +- req->completed = 1; +- condition_signal (&req->signal); +- mutex_unlock (&req->lock); ++ return err; + } + +-/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, +- then return EWOULDBLOCK immediately when there are no immediate +- connections available. Neither SOCK nor CQ should be locked. */ ++/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is ++ true, then return EWOULDBLOCK if there are no connections ++ immediately available. On success, this call must be followed up ++ either connq_connect_complete or connq_connect_cancel. */ + error_t +-connq_connect (struct connq *cq, int noblock, struct sock *sock) ++connq_connect (struct connq *cq, int noblock) + { +- error_t err = 0; +- unsigned next; +- + mutex_lock (&cq->lock); + + /* Check for listeners after we've locked CQ for good. */ +- if ((noblock || cq->noqueue) && cq->num_listeners == 0) ++ ++ if (noblock ++ && cq->count + cq->num_connectors >= cq->max + cq->num_listeners) ++ /* We are in non-blocking mode and would have to wait to secure an ++ entry in the listen queue. */ + { + mutex_unlock (&cq->lock); + return EWOULDBLOCK; + } + +- next = qnext (cq, cq->tail); +- if (next == cq->tail) +- /* The queue is full. */ +- err = ECONNREFUSED; +- else +- { +- struct connq_request req; ++ cq->num_connectors ++; ++ ++ while (cq->count + cq->num_connectors > cq->max + cq->num_listeners) ++ /* The queue is full and there is no immediate listener to service ++ us. Block until we can get a slot. */ ++ if (hurd_condition_wait (&cq->connectors, &cq->lock)) ++ { ++ cq->num_connectors --; ++ mutex_unlock (&cq->lock); ++ return EINTR; ++ } + +- connq_request_init (&req, sock); ++ mutex_unlock (&cq->lock); + +- cq->queue[cq->tail] = &req; +- cq->tail = next; ++ return 0; ++} + +- /* Hold REQ.LOCK before we signal the condition so that we're sure +- to be woken up. */ +- mutex_lock (&req.lock); +- condition_signal (&cq->listeners); +- mutex_unlock (&cq->lock); ++/* Follow up to connq_connect. Completes the connect, SOCK is the new ++ server socket. */ ++void ++connq_connect_complete (struct connq *cq, struct sock *sock) ++{ ++ struct connq_request *req; ++ ++ req = malloc (sizeof (struct connq_request)); ++ if (! req) ++ abort (); ++ ++ connq_request_init (req, sock); + +- while (!req.completed) +- condition_wait (&req.signal, &req.lock); +- err = req.err; ++ mutex_lock (&cq->lock); ++ ++ assert (cq->num_connectors > 0); ++ cq->num_connectors --; ++ ++ connq_request_enqueue (cq, req); + +- mutex_unlock (&req.lock); ++ if (cq->num_listeners > 0) ++ /* Wake a listener up. We must consume the listener ref here as ++ someone else might call this function before the listener ++ thread dequeues this request. */ ++ { ++ cq->num_listeners --; ++ condition_signal (&cq->listeners); + } + +- return err; ++ mutex_unlock (&cq->lock); + } +- +-#if 0 +-/* `Compresses' CQ, by removing any NULL entries. CQ should be locked. */ +-static void +-connq_compress (struct connq *cq) ++ ++/* Follow up to connq_connect. Cancel the connect. */ ++void ++connq_connect_cancel (struct connq *cq) + { +- unsigned pos; +- unsigned comp_tail = cq->head; ++ mutex_lock (&cq->lock); + +- /* Now compress the queue to remove any null entries we put in. */ +- for (pos = cq->head; pos != cq->tail; pos = qnext (cq, pos)) +- if (cq->queue[pos] != NULL) +- /* This position has a non-NULL request, so move it to the end of the +- compressed queue. */ +- { +- cq->queue[comp_tail] = cq->queue[pos]; +- comp_tail = qnext (cq, comp_tail); +- } ++ assert (cq->num_connectors > 0); ++ cq->num_connectors --; + +- /* Move back tail to only include what we kept in the queue. */ +- cq->tail = comp_tail; ++ if (cq->count + cq->num_connectors >= cq->max + cq->num_listeners) ++ /* A connector is blocked and could use the spot we reserved. */ ++ condition_signal (&cq->connectors); ++ ++ mutex_unlock (&cq->lock); + } +-#endif + +-/* Set CQ's queue length to LENGTH. Any sockets already waiting for a +- connections that are past the new length will fail with ECONNREFUSED. */ ++/* Set CQ's queue length to LENGTH. */ + error_t +-connq_set_length (struct connq *cq, int length) ++connq_set_length (struct connq *cq, int max) + { +- mutex_lock (&cq->lock); ++ int omax; + +- if (length > cq->length) +- /* Growing the queue is simple... */ +- cq->queue = realloc (cq->queue, sizeof (struct connq_request *) * length); +- else +- /* Shrinking it less so. */ +- { +- int i; +- struct connq_request **new_queue = +- malloc (sizeof (struct connq_request *) * length); +- +- for (i = 0; i < cq->length && cq->head != cq->tail; i++) +- { +- if (i < length) +- /* Keep this connect request in the queue. */ +- new_queue[length - i] = cq->queue[cq->head]; +- else +- /* Punt this one. */ +- connq_request_complete (cq->queue[cq->head], ECONNREFUSED); +- cq->head = qnext (cq, cq->head); +- } +- +- free (cq->queue); +- cq->queue = new_queue; +- } ++ mutex_lock (&cq->lock); ++ omax = cq->max; ++ cq->max = max; + +- cq->noqueue = 0; /* Turn on queueing. */ ++ if (max > omax && cq->count >= omax && cq->count < max ++ && cq->num_connectors >= cq->num_listeners) ++ /* This is an increase in the number of connection slots which has ++ made some slots available and there are waiting threads. Wake ++ them up. */ ++ condition_broadcast (&cq->listeners); + + mutex_unlock (&cq->lock); + +--- a/pflocal/connq.h ++++ b/pflocal/connq.h +@@ -23,9 +23,8 @@ + + #include <errno.h> + +-/* Unknown types */ ++/* Forward. */ + struct connq; +-struct connq_request; + struct sock; + + /* Create a new listening queue, returning it in CQ. The resulting queue +@@ -36,26 +35,26 @@ error_t connq_create (struct connq **cq) + /* Destroy a queue. */ + void connq_destroy (struct connq *cq); + +-/* Wait for a connection attempt to be made on CQ, and return the connecting +- socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is +- left in the queue, otherwise connq_request_complete must be called on REQ +- to allow the requesting thread to continue. If NOBLOCK is true, +- EWOULDBLOCK is returned when there are no immediate connections +- available. CQ should be unlocked. */ +-error_t connq_listen (struct connq *cq, int noblock, +- struct connq_request **req, struct sock **sock); +- +-/* Return the error code ERR to the thread that made the listen request REQ, +- returned from a previous connq_listen. */ +-void connq_request_complete (struct connq_request *req, error_t err); ++/* Return a connection request on CQ. If SOCK is NULL, the request is ++ left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned ++ when there are no immediate connections available. */ ++error_t connq_listen (struct connq *cq, int noblock, struct sock **sock); ++ ++/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is ++ true, then return EWOULDBLOCK if there are no connections ++ immediately available. On success, this call must be followed up ++ either connq_connect_complete or connq_connect_cancel. */ ++error_t connq_connect (struct connq *cq, int noblock); ++ ++/* Follow up to connq_connect. Completes the connection, SOCK is the ++ new server socket. */ ++void connq_connect_complete (struct connq *cq, struct sock *sock); ++ ++/* Follow up to connq_connect. Cancel the connect. */ ++void connq_connect_cancel (struct connq *cq); + + /* Set CQ's queue length to LENGTH. Any sockets already waiting for a +- connections that are past the new length will fail with ECONNREFUSED. */ ++ connections that are past the new length remain. */ + error_t connq_set_length (struct connq *cq, int length); + +-/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, +- then return EWOULDBLOCK immediately when there are no immediate +- connections available. Neither SOCK nor CQ should be locked. */ +-error_t connq_connect (struct connq *cq, int noblock, struct sock *sock); +- + #endif /* __CONNQ_H__ */ +--- a/pflocal/io.c ++++ b/pflocal/io.c +@@ -199,16 +199,16 @@ S_io_select (struct sock_user *user, + + if (*select_type & SELECT_READ) + { +- /* Wait for a connect. Passing in NULL for REQ means that the +- request won't be dequeued. */ +- if (connq_listen (sock->listen_queue, 1, NULL, NULL) == 0) ++ /* Wait for a connect. Passing in NULL for SOCK means that ++ the request won't be dequeued. */ ++ if (connq_listen (sock->listen_queue, 1, NULL) == 0) + /* We can satisfy this request immediately. */ + return 0; + else + /* Gotta wait... */ + { + ports_interrupt_self_on_port_death (user, reply); +- return connq_listen (sock->listen_queue, 0, NULL, NULL); ++ return connq_listen (sock->listen_queue, 0, NULL); + } + } + } +--- a/pflocal/socket.c ++++ b/pflocal/socket.c +@@ -110,7 +110,7 @@ S_socket_connect (struct sock_user *user + else if (sock->flags & SOCK_CONNECTED) + /* SOCK_CONNECTED is only set for connection-oriented sockets, + which can only ever connect once. [If we didn't do this test +- here, it would eventually fail when it the listening socket ++ here, it would eventually fail when the listening socket + tried to accept our connection request.] */ + err = EISCONN; + else +@@ -118,16 +118,35 @@ S_socket_connect (struct sock_user *user + /* Assert that we're trying to connect, so anyone else trying + to do so will fail with EALREADY. */ + sock->connect_queue = cq; +- mutex_unlock (&sock->lock); /* Unlock SOCK while waiting. */ ++ /* Unlock SOCK while waiting. */ ++ mutex_unlock (&sock->lock); + +- /* Try to connect. */ +- err = connq_connect (cq, sock->flags & SOCK_NONBLOCK, sock); ++ err = connq_connect (peer->listen_queue, ++ sock->flags & SOCK_NONBLOCK); ++ if (!err) ++ { ++ struct sock *server; ++ ++ err = sock_clone (peer, &server); ++ if (!err) ++ { ++ err = sock_connect (sock, server); ++ if (!err) ++ connq_connect_complete (peer->listen_queue, server); ++ else ++ sock_free (server); ++ } + +- /* We can safely set CONNECT_QUEUE to NULL, as no one else can ++ mutex_lock (&sock->lock); ++ if (err) ++ connq_connect_cancel (peer->listen_queue); ++ } ++ ++ /* We must set CONNECT_QUEUE to NULL, as no one else can + set it until we've done so. */ +- mutex_lock (&sock->lock); + sock->connect_queue = NULL; + } ++ + mutex_unlock (&sock->lock); + } + else +@@ -157,42 +176,25 @@ S_socket_accept (struct sock_user *user, + err = ensure_connq (sock); + if (!err) + { +- struct connq_request *req; + struct sock *peer_sock; + +- err = +- connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, +- &req, &peer_sock); ++ err = connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, ++ &peer_sock); + if (!err) + { +- struct sock *conn_sock; +- +- err = sock_clone (sock, &conn_sock); ++ struct addr *peer_addr; ++ *port_type = MACH_MSG_TYPE_MAKE_SEND; ++ err = sock_create_port (peer_sock, port); ++ if (!err) ++ err = sock_get_addr (peer_sock, &peer_addr); + if (!err) + { +- err = sock_connect (conn_sock, peer_sock); +- if (!err) +- { +- struct addr *peer_addr; +- *port_type = MACH_MSG_TYPE_MAKE_SEND; +- err = sock_create_port (conn_sock, port); +- if (!err) +- err = sock_get_addr (peer_sock, &peer_addr); +- if (!err) +- { +- *peer_addr_port = ports_get_right (peer_addr); +- *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; +- ports_port_deref (peer_addr); +- } +- else +- /* TEAR DOWN THE CONNECTION XXX */; +- } +- if (err) +- sock_free (conn_sock); ++ *peer_addr_port = ports_get_right (peer_addr); ++ *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; ++ ports_port_deref (peer_addr); + } +- +- /* Communicate any error (or success) to the connecting thread. */ +- connq_request_complete (req, err); ++ else ++ /* TEAR DOWN THE CONNECTION XXX */; + } + } + diff --git a/debian/patches/procfs.patch b/debian/patches/procfs.patch new file mode 100644 index 00000000..941c5507 --- /dev/null +++ b/debian/patches/procfs.patch @@ -0,0 +1,3218 @@ +Madhusudan's experimental procfs server for Linux-like /proc +--- + Makefile | 2 + procfs/ChangeLog | 161 ++++++++++ + procfs/Makefile | 30 + + procfs/bootstrap.c | 95 ++++++ + procfs/netfs.c | 466 ++++++++++++++++++++++++++++++ + procfs/node.c | 195 ++++++++++++ + procfs/procfs.c | 149 +++++++++ + procfs/procfs.h | 220 ++++++++++++++ + procfs/procfs_dir.c | 664 +++++++++++++++++++++++++++++++++++++++++++ + procfs/procfs_nonpid_files.c | 514 +++++++++++++++++++++++++++++++++ + procfs/procfs_pid.h | 88 +++++ + procfs/procfs_pid_files.c | 576 +++++++++++++++++++++++++++++++++++++ + 12 files changed, 3159 insertions(+), 1 deletion(-) + +--- /dev/null ++++ b/procfs/ChangeLog +@@ -0,0 +1,161 @@ ++2008-08-30 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * procfs_dir.c: (procfs_dir_create): Assign newly created directory to ++ its pointer in netnode. ++ (procfs_dir_remove): Removed function. ++ (free_entry): New function. ++ (ordered_unlink): Likewise. ++ (delete): Likewise. ++ (sweep): Likewise. ++ (procfs_dir_entries_remove): Likewise. ++ (is_in_pid_list): Removed call to make_dir_invalid (). ++ (procfs_fill_root_dir): struct stat *stat -> struct stat stat. ++ Add Read and Execute permissions to all in stat.st_mode. ++ Set stat.st_nlink to 1. ++ Set stat.st_size to 0. ++ Add struct proc_stat *ps definition. ++ Set struct proc_stat data from _proc_stat_create () function and ++ set stat.st_uid and stat.st_gid from the data in that structure. ++ * procfs_pid_files.c: (update_pid_entries): Add Read permissions ++ to all in stat->st_mode. ++ ++2008-08-29 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * AUTHORS: File removed. ++ * COPYING: Likewise. ++ * README: Likewise. ++ ++2008-08-29 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * Makefile: (Copyright): 1997, 2000 -> 2008. ++ (CC): Removed. ++ (CFLAGS): Removed. ++ (INCLUDES): Removed. ++ (all): Removed. ++ ($(target)): Removed. ++ (%.o): Removed. ++ (HURDLIBS): -lnetfs -> netfs, -lfshelp -> fshelp, ++ -liohelp -> iohelp, -lthreads -> threads, -lports -> ports, ++ -lihash -> ihash, -lps -> ps, -lshouldbeinlibc -> shouldbeinlibc. ++ (include): Add include ../Makeconf ++ ++2008-08-18 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * procfs_nonpid_files.c: (procfs_write_nonpid_stat): Changed to ++ procfs_read_nonpid_stat. ++ (procfs_write_nonpid_meminfo): Changed to procfs_read_nonpid_meminfo. ++ (procfs_write_nonpid_loadavg): Changed to procfs_read_nonpid_loadavg. ++ (procfs_write_nonpid_uptime): Changed to procfs_read_nonpid_uptime. ++ (procfs_write_nonpid_version):Changed to procfs_read_nonpid_version. ++ * procfs_pid_files.c: (procfs_write_stat_file): Changed to ++ procfs_read_stat_file. ++ Changed the comment correspondingly from Write to Read. ++ (procfs_write_cmdline_file ): Changed to procfs_read_cmdline_file. ++ Changed the comment correspondingly from Write to Read. ++ (procfs_write_status_file): Changed to procfs_read_status_file. ++ Changed the comment correspondingly from Write to Read. ++ (procfs_write_statm_file): Changed to procfs_read_statm_file. ++ Changed the comment correspondingly from Write to Read. ++ (procfs_write_files_contents): Changed to procfs_read_files_contents. ++ Changed the comment correspondingly from Write to Read. ++ Changed the call to procfs_write_nonpid_stat to procfs_read_nonpid_stat. ++ Changed the call to procfs_write_stat_file to procfs_read_stat_file. ++ Changed the call to procfs_write_cmdline_file to ++ procfs_read_cmdline_file. ++ Changed the call to procfs_write_status_file to ++ procfs_read_status_file. ++ Changed the call to procfs_write_statm_file to ++ procfs_read_statm_file. ++ Changed the call to procfs_write_nonpid_meminfo to ++ procfs_read_nonpid_meminfo. ++ Changed the call to procfs_write_nonpid_loadavg to ++ procfs_read_nonpid_loadavg. ++ Changed the call to procfs_write_nonpid_uptime to ++ procfs_read_nonpid_uptime. ++ Changed the call to procfs_write_nonpid_version to ++ procfs_read_nonpid_version. ++ netfs.c: (netfs_attempt_read): Changed the call from ++ procfs_write_files_contents to procfs_read_files_contents. ++ ++2008-08-18 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * README: Initial Documentation. ++ ++2008-08-18 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * procfs_nonpid_files.c: (get_uptime): Changed the parameter type from ++ double to struct timeval. ++ Changed the parameter name from uptime_secs to uptime. ++ Removed uptime variable. ++ Changed timersub to use the passed pointer instead of the local ++ variable. ++ Removed the calculation of uptime_secs. ++ (get_total_times): Changed the parameters type from double to struct ++ timeval. ++ Changed the parameters name from total_user_time_secs to ++ total_user_time and total_system_time_secs to total_system_time. ++ New variables total_user_time_tmp, total_system_time_tmp and tmpval ++ of type struct timeval. ++ Call timerclear to clear the tmp variables. ++ Remove calculation of times in seconds and do the same on struct ++ timeval variables throughout using the timeradd macro. ++ Assign values of temporary local variables to the pointers passed ++ as parameters. ++ (procfs_write_nonpid_stat): Replaced variables that hold time in ++ seconds with struct timeval type variables and jiffy_t type variables. ++ Argument to get_uptime changed from uptime_secs to uptime. ++ Arguments to get_total_times changed from total_user_time_secs to ++ total_user_time and total_system_time_secs to total_system_time. ++ Replace arithematic time subtraction with timersub macro. ++ Convert all the times in struct timeval type variables to jiffy_t type. ++ Changed the type casting for the asprintf arguments to be compatible ++ with jiffy_t type. ++ (procfs_write_nonpid_uptime): Replaced variables that hold time in ++ seconds with struct timeval type variables. ++ Argument to get_uptime changed from uptime_secs to uptime. ++ Arguments to get_total_times changed from total_user_time_secs to ++ total_user_time and total_system_time_secs to total_system_time. ++ Replace arithematic time subtraction with timersub macro. ++ Convert all the times in struct timeval type variables to seconds. ++ ++2008-08-18 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * procfs_nonpid_files.c: (procfs_write_nonpid_version): New function. ++ * procfs_pid_files.c: (procfs_write_files_contents): Add a check ++ to find if the read is requested for the version file and ++ corresponding a call to it. ++ ++2008-08-14 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * procfs.h: (jiffy_t): New typedef. ++ * procfs_pid.h: "procfs.h" is included. ++ (struct procfs_pid_files): Changed all the occurrences of time_t to ++ jiffy_t. ++ * procfs_pid_files.c: Removed "procfs.h". ++ (adjust_jiffy_time): Changed return type from time_t to jiffy_t. ++ Changed the type of jiffy_time variable from time_t to jiffy_t. ++ (get_live_threads_time): Changed the type of utime and stime from ++ time_t to jiffy_t. ++ (get_stat_data): Changed the type of utime and stime from time_t to ++ jiffy_t. ++ ++2008-08-14 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * ChangeLog: New file. ++ * AUTHORS: New file. ++ * COPYING: New file. ++ * README: New file. ++ * Makefile: New file. ++ * bootstrap.c: New file. ++ * netfs.c: New file. ++ * node.c: New file. ++ * procfs.c: New file. ++ * procfs.h: New file. ++ * procfs_dir.c: New file. ++ * procfs_nonpid_files.c: New file. ++ * procfs_pid.h: New file. ++ * procfs_pid_files.c: New file. ++ ++2008-05-13 Madhusudan.C.S <madhusudancs@gmail.com> ++ ++ * /sources/hurd/procfs: New directory added to the repository. +--- /dev/null ++++ b/procfs/Makefile +@@ -0,0 +1,30 @@ ++# Makefile - for procfs ++# ++# Copyright (C) 2008 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2, or (at ++# your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++dir := procfs ++makemode := server ++ ++target = procfs ++ ++SRCS = procfs.c bootstrap.c netfs.c procfs_dir.c node.c procfs_pid_files.c procfs_nonpid_files.c ++LCLHDRS = procfs.h procfs_pid.h ++ ++OBJS = $(SRCS:.c=.o) ++HURDLIBS = netfs fshelp iohelp threads ports ihash ps shouldbeinlibc ++ ++include ../Makeconf +--- /dev/null ++++ b/procfs/bootstrap.c +@@ -0,0 +1,95 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ bootstrap.c -- This file is functions for starting up ++ and initializers for the procfs translator ++ defined in procfs.h ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++*/ ++ ++#include <stddef.h> ++#include <hurd/ihash.h> ++#include <hurd/netfs.h> ++ ++#include "procfs.h" ++ ++struct ps_context *ps_context; ++ ++/* This function is used to initialize the whole translator, can be ++ effect called as bootstrapping the translator. */ ++error_t procfs_init () ++{ ++ error_t err; ++ ++ err = ps_context_create (getproc (), &ps_context); ++ ++ return err; ++} ++ ++/* Create a new procfs filesystem. */ ++error_t procfs_create (char *procfs_root, int fsid, ++ struct procfs **fs) ++{ ++ error_t err; ++ /* This is the enclosing directory for this filesystem's ++ root node */ ++ struct procfs_dir *topmost_root_dir; ++ ++ /* And also a topmost-root node, just used for locking ++ TOPMOST_ROOT_DIR. */ ++ struct node *topmost_root; ++ ++ /* The new node for the filesystem's root. */ ++ struct procfs *new = malloc (sizeof (struct procfs)); ++ ++ if (! new) ++ return ENOMEM; ++ ++ new->fsid = fsid; ++ new->next_inode = 2; ++ ++ hurd_ihash_init (&new->inode_mappings, ++ offsetof (struct procfs_dir_entry, inode_locp)); ++ spin_lock_init (&new->inode_mappings_lock); ++ ++ topmost_root = netfs_make_node (0); ++ if (! topmost_root) ++ err = ENOMEM; ++ else ++ { ++ err = procfs_dir_create (new, topmost_root, procfs_root, ++ &topmost_root_dir); ++ if (! err) ++ { ++ /* ADDITIONAL BOOTSTRAPPING OF THE ROOT NODE */ ++ err = procfs_dir_null_lookup (topmost_root_dir, &new->root); ++ } ++ } ++ ++ if (err) ++ { ++ hurd_ihash_destroy (&new->inode_mappings); ++ free (new); ++ } ++ else ++ *fs = new; ++ ++ return err; ++} ++ +--- /dev/null ++++ b/procfs/netfs.c +@@ -0,0 +1,466 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++*/ ++ ++#include <stddef.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <unistd.h> ++#include <dirent.h> ++#include <string.h> ++ ++#include <sys/mman.h> ++#include <sys/stat.h> ++#include <hurd/netfs.h> ++ ++#include "procfs.h" ++ ++/* Trivial definitions. */ ++ ++/* Make sure that NP->nn_stat is filled with current information. CRED ++ identifies the user responsible for the operation. */ ++error_t ++netfs_validate_stat (struct node *node, struct iouser *cred) ++{ ++ return procfs_refresh_node (node); ++} ++ ++/* This should sync the file NODE completely to disk, for the user CRED. If ++ WAIT is set, return only after sync is completely finished. */ ++error_t ++netfs_attempt_sync (struct iouser *cred, struct node *node, int wait) ++{ ++ return 0; ++} ++ ++/* Attempt to create a new directory named NAME in DIR for USER with mode ++ MODE. */ ++error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir, ++ char *name, mode_t mode) ++{ ++ return EROFS; ++} ++ ++/* Attempt to remove directory named NAME in DIR for USER. */ ++error_t netfs_attempt_rmdir (struct iouser *user, ++ struct node *dir, char *name) ++{ ++ return EROFS; ++} ++ ++/* Attempt to set the passive translator record for FILE to ARGZ (of length ++ ARGZLEN) for user CRED. */ ++error_t netfs_set_translator (struct iouser *cred, struct node *node, ++ char *argz, size_t argzlen) ++{ ++ return EROFS; ++} ++ ++/* Attempt to create a file named NAME in DIR for USER with MODE. Set *NODE ++ to the new node upon return. On any error, clear *NODE. *NODE should be ++ locked on success; no matter what, unlock DIR before returning. */ ++error_t ++netfs_attempt_create_file (struct iouser *user, struct node *dir, ++ char *name, mode_t mode, struct node **node) ++{ ++ *node = NULL; ++ mutex_unlock (&dir->lock); ++ return EROFS; ++} ++ ++/* Node NODE is being opened by USER, with FLAGS. NEWNODE is nonzero if we ++ just created this node. Return an error if we should not permit the open ++ to complete because of a permission restriction. */ ++error_t ++netfs_check_open_permissions (struct iouser *user, struct node *node, ++ int flags, int newnode) ++{ ++ error_t err = procfs_refresh_node (node); ++ if (!err && (flags & O_READ)) ++ err = fshelp_access (&node->nn_stat, S_IREAD, user); ++ if (!err && (flags & O_WRITE)) ++ err = fshelp_access (&node->nn_stat, S_IWRITE, user); ++ if (!err && (flags & O_EXEC)) ++ err = fshelp_access (&node->nn_stat, S_IEXEC, user); ++ return err; ++} ++ ++/* This should attempt a utimes call for the user specified by CRED on node ++ NODE, to change the atime to ATIME and the mtime to MTIME. */ ++error_t ++netfs_attempt_utimes (struct iouser *cred, struct node *node, ++ struct timespec *atime, struct timespec *mtime) ++{ ++ error_t err = procfs_refresh_node (node); ++ int flags = TOUCH_CTIME; ++ ++ if (! err) ++ err = fshelp_isowner (&node->nn_stat, cred); ++ ++ if (! err) ++ { ++ if (atime) ++ node->nn_stat.st_atim = *atime; ++ else ++ flags |= TOUCH_ATIME; ++ ++ if (mtime) ++ node->nn_stat.st_mtim = *mtime; ++ else ++ flags |= TOUCH_MTIME; ++ ++ fshelp_touch (&node->nn_stat, flags, procfs_maptime); ++ } ++ ++ return err; ++} ++ ++/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and O_EXEC) ++ in *TYPES for file NODE and user CRED. */ ++error_t ++netfs_report_access (struct iouser *cred, struct node *node, int *types) ++{ ++ error_t err = procfs_refresh_node (node); ++ ++ if (! err) ++ { ++ *types = 0; ++ if (fshelp_access (&node->nn_stat, S_IREAD, cred) == 0) ++ *types |= O_READ; ++ if (fshelp_access (&node->nn_stat, S_IWRITE, cred) == 0) ++ *types |= O_WRITE; ++ if (fshelp_access (&node->nn_stat, S_IEXEC, cred) == 0) ++ *types |= O_EXEC; ++ } ++ ++ return err; ++} ++ ++/* The granularity with which we allocate space to return our result. */ ++#define DIRENTS_CHUNK_SIZE (8*1024) ++ ++/* Returned directory entries are aligned to blocks this many bytes long. ++ Must be a power of two. */ ++#define DIRENT_ALIGN 4 ++#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name) ++ ++/* Length is structure before the name + the name + '\0', all ++ padded to a four-byte alignment. */ ++#define DIRENT_LEN(name_len) \ ++ ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \ ++ & ~(DIRENT_ALIGN - 1)) ++ ++ ++ ++/* Fetch a directory */ ++error_t ++netfs_get_dirents (struct iouser *cred, struct node *dir, ++ int first_entry, int max_entries, char **data, ++ mach_msg_type_number_t *data_len, ++ vm_size_t max_data_len, int *data_entries) ++{ ++ error_t err = procfs_refresh_node (dir); ++ struct procfs_dir_entry *dir_entry; ++ ++ if (! err) ++ { ++ if (dir->nn->dir) ++ { ++ if (! procfs_dir_refresh (dir->nn->dir, dir == dir->nn->fs->root)) ++ { ++ for (dir_entry = dir->nn->dir->ordered; first_entry > 0 && ++ dir_entry; first_entry--, ++ dir_entry = dir_entry->ordered_next); ++ if (! dir_entry ) ++ max_entries = 0; ++ ++ if (max_entries != 0) ++ { ++ size_t size = 0; ++ char *p; ++ int count = 0; ++ ++ ++ if (max_data_len == 0) ++ size = DIRENTS_CHUNK_SIZE; ++ else if (max_data_len > DIRENTS_CHUNK_SIZE) ++ size = DIRENTS_CHUNK_SIZE; ++ else ++ size = max_data_len; ++ ++ *data = mmap (0, size, PROT_READ|PROT_WRITE, ++ MAP_ANON, 0, 0); ++ ++ err = ((void *) *data == (void *) -1) ? errno : 0; ++ ++ if (! err) ++ { ++ p = *data; ++ ++ /* This gets all the actual entries present. */ ++ ++ while ((max_entries == -1 || count < max_entries) && dir_entry) ++ { ++ struct dirent hdr; ++ size_t name_len = strlen (dir_entry->name); ++ size_t sz = DIRENT_LEN (name_len); ++ int entry_type = IFTODT (dir_entry->stat.st_mode); ++ ++ if ((p - *data) + sz > size) ++ { ++ if (max_data_len > 0) ++ break; ++ else /* The Buffer Size must be increased. */ ++ { ++ vm_address_t extension = (vm_address_t)(*data + size); ++ err = vm_allocate (mach_task_self (), &extension, ++ DIRENTS_CHUNK_SIZE, 0); ++ ++ if (err) ++ break; ++ ++ size += DIRENTS_CHUNK_SIZE; ++ } ++ } ++ ++ hdr.d_namlen = name_len; ++ hdr.d_fileno = dir_entry->stat.st_ino; ++ hdr.d_reclen = sz; ++ hdr.d_type = entry_type; ++ ++ memcpy (p, &hdr, DIRENT_NAME_OFFS); ++ strcpy (p + DIRENT_NAME_OFFS, dir_entry->name); ++ ++ p += sz; ++ ++ count++; ++ dir_entry = dir_entry->ordered_next; ++ } ++ ++ if (err) ++ munmap (*data, size); ++ else ++ { ++ vm_address_t alloc_end = (vm_address_t)(*data + size); ++ vm_address_t real_end = round_page (p); ++ if (alloc_end > real_end) ++ munmap ((caddr_t) real_end, alloc_end - real_end); ++ *data_len = p - *data; ++ *data_entries = count; ++ } ++ } ++ } ++ else ++ { ++ *data_len = 0; ++ *data_entries = 0; ++ } ++ } ++ } ++ else ++ return ENOTDIR; ++ } ++ procfs_dir_entries_remove (dir->nn->dir); ++ return err; ++} ++ ++/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If ++ the name was not found, then return ENOENT. On any error, clear *NODE. ++ (*NODE, if found, should be locked, this call should unlock DIR no matter ++ what.) */ ++error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, ++ char *name, struct node **node) ++{ ++ error_t err = procfs_refresh_node (dir); ++ ++ if (! err) ++ err = procfs_dir_lookup (dir->nn->dir, name, node); ++ ++ return err; ++} ++ ++/* Delete NAME in DIR for USER. */ ++error_t netfs_attempt_unlink (struct iouser *user, struct node *dir, ++ char *name) ++{ ++ return EROFS; ++} ++ ++/* Note that in this one call, neither of the specific nodes are locked. */ ++error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir, ++ char *fromname, struct node *todir, ++ char *toname, int excl) ++{ ++ return EROFS; ++} ++ ++/* This should attempt a chmod call for the user specified by CRED on node ++ NODE, to change the owner to UID and the group to GID. */ ++error_t netfs_attempt_chown (struct iouser *cred, struct node *node, ++ uid_t uid, uid_t gid) ++{ ++ return EROFS; ++} ++ ++/* This should attempt a chauthor call for the user specified by CRED on node ++ NODE, to change the author to AUTHOR. */ ++error_t netfs_attempt_chauthor (struct iouser *cred, struct node *node, ++ uid_t author) ++{ ++ return EROFS; ++} ++ ++/* This should attempt a chmod call for the user specified by CRED on node ++ NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning ++ of chmod, this function is also used to attempt to change files into other ++ types. If such a transition is attempted which is impossible, then return ++ EOPNOTSUPP. */ ++error_t netfs_attempt_chmod (struct iouser *cred, struct node *node, ++ mode_t mode) ++{ ++ return EROFS; ++} ++ ++/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */ ++error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *node, ++ char *name) ++{ ++ return EROFS; ++} ++ ++/* Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or ++ S_IFCHR. */ ++error_t netfs_attempt_mkdev (struct iouser *cred, struct node *node, ++ mode_t type, dev_t indexes) ++{ ++ return EROFS; ++} ++ ++ ++/* This should attempt a chflags call for the user specified by CRED on node ++ NODE, to change the flags to FLAGS. */ ++error_t netfs_attempt_chflags (struct iouser *cred, struct node *node, ++ int flags) ++{ ++ return EROFS; ++} ++ ++/* This should attempt to set the size of the file NODE (for user CRED) to ++ SIZE bytes long. */ ++error_t netfs_attempt_set_size (struct iouser *cred, struct node *node, ++ off_t size) ++{ ++ return EROFS; ++} ++ ++/* This should attempt to fetch filesystem status information for the remote ++ filesystem, for the user CRED. */ ++error_t ++netfs_attempt_statfs (struct iouser *cred, struct node *node, ++ struct statfs *st) ++{ ++ bzero (st, sizeof *st); ++ st->f_type = PROCFILESYSTEM; ++ st->f_fsid = getpid (); ++ return 0; ++} ++ ++/* This should sync the entire remote filesystem. If WAIT is set, return ++ only after sync is completely finished. */ ++error_t netfs_attempt_syncfs (struct iouser *cred, int wait) ++{ ++ return 0; ++} ++ ++/* Create a link in DIR with name NAME to FILE for USER. Note that neither ++ DIR nor FILE are locked. If EXCL is set, do not delete the target, but ++ return EEXIST if NAME is already found in DIR. */ ++error_t netfs_attempt_link (struct iouser *user, struct node *dir, ++ struct node *file, char *name, int excl) ++{ ++ return EROFS; ++} ++ ++/* Attempt to create an anonymous file related to DIR for USER with MODE. ++ Set *NODE to the returned file upon success. No matter what, unlock DIR. */ ++error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir, ++ mode_t mode, struct node **node) ++{ ++ *node = NULL; ++ mutex_unlock (&dir->lock); ++ return EROFS; ++} ++ ++/* Read the contents of NODE (a symlink), for USER, into BUF. */ ++error_t netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf) ++{ ++ error_t err = procfs_refresh_node (node); ++ if (! err) ++ { ++ struct procfs_dir_entry *dir_entry = node->nn->dir_entry; ++ if (dir_entry) ++ bcopy (dir_entry->symlink_target, buf, node->nn_stat.st_size); ++ else ++ err = EINVAL; ++ } ++ return err; ++} ++ ++/* Read from the file NODE for user CRED starting at OFFSET and continuing for ++ up to *LEN bytes. Put the data at DATA. Set *LEN to the amount ++ successfully read upon return. */ ++error_t netfs_attempt_read (struct iouser *cred, struct node *node, ++ off_t offset, size_t *len, void *data) ++{ ++ error_t err; ++ err = procfs_refresh_node (node); ++ ++ if (! err) ++ { ++ if (*len > 0) ++ procfs_read_files_contents (node, offset, ++ len, data); ++ if (*len > 0) ++ if (offset >= *len) ++ *len = 0; ++ } ++ ++ return err; ++} ++ ++/* Write to the file NODE for user CRED starting at OFFSET and continuing for up ++ to *LEN bytes from DATA. Set *LEN to the amount seccessfully written upon ++ return. */ ++error_t netfs_attempt_write (struct iouser *cred, struct node *node, ++ off_t offset, size_t *len, void *data) ++{ ++ return EROFS; ++} ++ ++/* The user must define this function. Node NP is all done; free ++ all its associated storage. */ ++void netfs_node_norefs (struct node *np) ++{ ++ mutex_lock (&np->lock); ++ *np->prevp = np->next; ++ np->next->prevp = np->prevp; ++ procfs_remove_node (np); ++} ++ +--- /dev/null ++++ b/procfs/node.c +@@ -0,0 +1,195 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ node.c -- This file contains function defintions to handle ++ node creation and destruction. ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++*/ ++#include <stdio.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <string.h> ++#include <errno.h> ++#include <hurd/ihash.h> ++#include <hurd/fshelp.h> ++#include <hurd/iohelp.h> ++ ++#include <hurd/netfs.h> ++ ++#include "procfs.h" ++ ++/* Return a new node in NODE, with a name NAME, and return the ++ new node with a single reference in NODE. */ ++error_t procfs_create_node (struct procfs_dir_entry *dir_entry, ++ const char *fs_path, struct node **node) ++{ ++ struct node *new; ++ struct netnode *nn = malloc (sizeof (struct netnode)); ++ error_t err; ++ ++ if (! nn) ++ return ENOMEM; ++ if (! fs_path) ++ fs_path = strdup (""); ++ nn->fs = dir_entry->dir->fs; ++ nn->dir_entry = dir_entry; ++ nn->dir = NULL; ++ nn->fs_path = strdup (fs_path); ++ ++ new = netfs_make_node (nn); ++ if (! new) ++ { ++ free (nn); ++ return ENOMEM; ++ } ++ ++ fshelp_touch (&new->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, ++ procfs_maptime); ++ ++ spin_lock (&nn->fs->inode_mappings_lock); ++ err = hurd_ihash_add (&nn->fs->inode_mappings, dir_entry->stat.st_ino, dir_entry); ++ spin_unlock (&nn->fs->inode_mappings_lock); ++ ++ if (err) ++ { ++ free (nn); ++ free (new); ++ return err; ++ } ++ ++ dir_entry->node = new; ++ *node = new; ++ ++ return 0; ++} ++ ++/* Update the directory entry for NAME to reflect ST and SYMLINK_TARGET. ++ True is returned if successful, or false if there was a memory allocation ++ error. TIMESTAMP is used to record the time of this update. */ ++static void ++update_entry (struct procfs_dir_entry *dir_entry, const struct stat *st, ++ const char *symlink_target, time_t timestamp) ++{ ++ ino_t ino; ++ struct procfs *fs = dir_entry->dir->fs; ++ ++ if (dir_entry->stat.st_ino) ++ ino = dir_entry->stat.st_ino; ++ else ++ ino = fs->next_inode++; ++ ++ dir_entry->name_timestamp = timestamp; ++ ++ if (st) ++ /* The ST and SYMLINK_TARGET parameters are only valid if ST isn't 0. */ ++ { ++ dir_entry->stat = *st; ++ dir_entry->stat_timestamp = timestamp; ++ ++ if (!dir_entry->symlink_target || !symlink_target ++ || strcmp (dir_entry->symlink_target, symlink_target) != 0) ++ { ++ if (dir_entry->symlink_target) ++ free (dir_entry->symlink_target); ++ dir_entry->symlink_target = symlink_target ? strdup (symlink_target) : 0; ++ } ++ } ++ ++ /* The st_ino field is always valid. */ ++ dir_entry->stat.st_ino = ino; ++ dir_entry->stat.st_fsid = fs->fsid; ++ dir_entry->stat.st_fstype = PROCFILESYSTEM; ++} ++ ++/* Refresh stat information for NODE */ ++error_t procfs_refresh_node (struct node *node) ++{ ++ struct netnode *nn = node->nn; ++ struct procfs_dir_entry *dir_entry = nn->dir_entry; ++ ++ if (! dir_entry) ++ /* This is a deleted node, don't attempt to do anything. */ ++ return 0; ++ else ++ { ++ error_t err = 0; ++ ++ struct timeval tv; ++ maptime_read (procfs_maptime, &tv); ++ ++ time_t timestamp = tv.tv_sec; ++ ++ struct procfs_dir *dir = dir_entry->dir; ++ ++ mutex_lock (&dir->node->lock); ++ ++ if (! dir_entry->self_p) ++ /* This is a deleted entry, just awaiting disposal; do so. */ ++ { ++#if 0 ++ nn->dir_entry = 0; ++ free_entry (dir_entry); ++ return 0; ++#endif ++ } ++ ++ else if (dir_entry->noent) ++ err = ENOENT; ++ else ++ { ++ if (*(dir_entry->name)) ++ { ++ err = procfs_dir_refresh (dir_entry->dir, ++ dir_entry->dir->node == dir_entry->dir->fs->root); ++ if (!err && dir_entry->noent) ++ err = ENOENT; ++ ++ if (err == ENOENT) ++ { ++ dir_entry->noent = 1; /* A negative entry. */ ++ dir_entry->name_timestamp = timestamp; ++ } ++ } ++ else ++ { ++ /* Refresh the root node with the old stat ++ information. */ ++ update_entry (dir_entry, &netfs_root_node->nn_stat, NULL, timestamp); ++ } ++ } ++ ++ node->nn_stat = dir_entry->stat; ++ node->nn_translated = S_ISLNK (dir_entry->stat.st_mode) ? S_IFLNK : 0; ++ if (!nn->dir && S_ISDIR (dir_entry->stat.st_mode)) ++ procfs_dir_create (nn->fs, node, nn->fs_path, &nn->dir); ++ ++ mutex_unlock (&dir->node->lock); ++ ++ return err; ++ } ++} ++ ++/* Remove NODE from its entry */ ++error_t procfs_remove_node (struct node *node) ++{ ++ ++ /* STUB */ ++ ++ return 0; ++} +--- /dev/null ++++ b/procfs/procfs.c +@@ -0,0 +1,149 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs.c -- This file is the main file of the translator. ++ This has important definitions and initializes ++ the translator ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++*/ ++ ++#include <stdio.h> ++#include <argp.h> ++#include <string.h> ++#include <stdlib.h> ++ ++#include <unistd.h> ++#include <error.h> ++#include <sys/stat.h> ++#include <hurd/netfs.h> ++ ++#include "procfs.h" ++ ++/* Defines this Tanslator Name */ ++char *netfs_server_name = PROCFS_SERVER_NAME; ++char *netfs_server_version = PROCFS_SERVER_VERSION; ++int netfs_maxsymlinks = 12; ++ ++static const struct argp_child argp_children[] = ++ { ++ {&netfs_std_startup_argp, 0, NULL, 0}, ++ {0} ++ }; ++ ++ ++const char *argp_program_version = "/proc pseudo-filesystem (" PROCFS_SERVER_NAME ++ ") " PROCFS_SERVER_VERSION "\n" ++"Copyright (C) 2008 Free Software Foundation\n" ++"This is free software; see the source for copying conditions. There is NO\n" ++"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." ++"\n"; ++ ++static char *args_doc = "PROCFSROOT"; ++static char *doc = "proc pseudo-filesystem for Hurd implemented as a translator. " ++"This is still under very humble and initial stages of development.\n" ++"Any Contribution or help is welcome. The code may not even compile"; ++ ++ ++/* The Filesystem */ ++struct procfs *procfs; ++ ++/* The FILESYSTEM component of PROCFS_FS. */ ++char *procfs_root = ""; ++ ++volatile struct mapped_time_value *procfs_maptime; ++ ++/* Startup options. */ ++static const struct argp_option procfs_options[] = ++ { ++ { 0 } ++ }; ++ ++ ++/* argp parser function for parsing single procfs command line options */ ++static error_t ++parse_procfs_opt (int key, char *arg, struct argp_state *state) ++{ ++ switch (key) ++ { ++ case ARGP_KEY_ARG: ++ if (state->arg_num > 1) ++ argp_usage (state); ++ break; ++ ++ case ARGP_KEY_NO_ARGS: ++ argp_usage(state); ++ break; ++ ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++} ++ ++/* Program entry point. */ ++int ++main (int argc, char **argv) ++{ ++ error_t err; ++ mach_port_t bootstrap, underlying_node; ++ struct stat underlying_stat; ++ ++ struct argp argp = ++ { ++ procfs_options, parse_procfs_opt, ++ args_doc, doc, argp_children, ++ NULL, NULL ++ }; ++ ++ ++ /* Parse the command line arguments */ ++// argp_parse (&argp, argc, argv, 0, 0, 0); ++ ++ task_get_bootstrap_port (mach_task_self (), &bootstrap); ++ ++ netfs_init (); ++ ++ if (maptime_map (0, 0, &procfs_maptime)) ++ { ++ perror (PROCFS_SERVER_NAME ": Cannot map time"); ++ return 1; ++ } ++ ++ procfs_init (); ++ ++ err = procfs_create (procfs_root, getpid (), &procfs); ++ if (err) ++ error (4, err, "%s", procfs_root); ++ ++ /* Create our root node */ ++ netfs_root_node = procfs->root; ++ ++ /* Start netfs activities */ ++ underlying_node = netfs_startup (bootstrap, 0); ++ if (io_stat (underlying_node, &underlying_stat)) ++ error (1, err, "cannot stat underling node"); ++ ++ /* Initialize stat information of the root node. */ ++ netfs_root_node->nn_stat = underlying_stat; ++ netfs_root_node->nn_stat.st_mode = ++ S_IFDIR | (underlying_stat.st_mode & ~S_IFMT & ~S_ITRANS); ++ ++ for (;;) ++ netfs_server_loop (); ++ return 1; ++} +--- /dev/null ++++ b/procfs/procfs.h +@@ -0,0 +1,220 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs.h -- This file is the main header file of this ++ translator. This has important header ++ definitions for constants and functions ++ used in the translator. ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++ ++ A portion of the code in this file is based on ftpfs code ++ present in the hurd repositories copyrighted to FSF. The ++ Copyright notice from that file is given below. ++ ++ Copyright (C) 1997,98,2002 Free Software Foundation, Inc. ++ Written by Miles Bader <miles@gnu.org> ++ This file is part of the GNU Hurd. ++*/ ++ ++#ifndef __PROCFS_H__ ++#define __PROCFS_H__ ++ ++#define PROCFS_SERVER_NAME "procfs" ++#define PROCFS_SERVER_VERSION "0.0.1" ++ ++/* /proc Filesystem type. */ ++#define PROCFILESYSTEM "procfs" ++ ++#define NUMBER_OF_FILES_PER_PID 1 ++#define JIFFY_ADJUST 100 ++#define PAGES_TO_BYTES(pages) ((pages) * sysconf(_SC_PAGESIZE)) ++#define BYTES_TO_PAGES(bytes) ((bytes) / sysconf(_SC_PAGESIZE)) ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <cthreads.h> ++#include <maptime.h> ++#include <hurd/ihash.h> ++#include <ps.h> ++ ++typedef unsigned long long jiffy_t; ++ ++/* A single entry in a directory. */ ++struct procfs_dir_entry ++{ ++ char *name; /* Name of this entry */ ++ size_t hv; /* Hash value of NAME */ ++ ++ /* The active node referred to by this name (may be 0). ++ NETFS_NODE_REFCNT_LOCK should be held while frobbing this. */ ++ struct node *node; ++ ++ struct stat stat; ++ char *symlink_target; ++ time_t stat_timestamp; ++ ++ /* The directory to which this entry belongs. */ ++ struct procfs_dir *dir; ++ ++ /* Link to next entry in hash bucket, and address of previous entry's (or ++ hash table's) pointer to this entry. If the SELF_P field is 0, then ++ this is a deleted entry, awaiting final disposal. */ ++ struct procfs_dir_entry *next, **self_p; ++ ++ /* Next entry in 'directory order', or 0 if none known. */ ++ struct procfs_dir_entry *ordered_next, **ordered_self_p; ++ ++ /* When the presence/absence of this file was last checked. */ ++ time_t name_timestamp; ++ ++ hurd_ihash_locp_t inode_locp; /* Used for removing this entry */ ++ ++ int noent : 1; /* A negative lookup result. */ ++ int valid : 1; /* Marker for GC'ing. */ ++}; ++ ++/* A directory. */ ++struct procfs_dir ++{ ++ /* Number of entries in HTABLE. */ ++ size_t num_entries; ++ ++ /* The number of entries that have nodes attached. We keep an additional ++ reference to our node if there are any, to prevent it from going away. */ ++ size_t num_live_entries; ++ ++ /* Hash table of entries. */ ++ struct procfs_dir_entry **htable; ++ size_t htable_len; /* # of elements in HTABLE (not bytes). */ ++ ++ /* List of dir entries in 'directory order', in a linked list using the ++ ORDERED_NEXT and ORDERED_SELF_P fields in each entry. Not all entries ++ in HTABLE need be in this list. */ ++ struct procfs_dir_entry *ordered; ++ ++ /* The filesystem node that this is the directory for. */ ++ struct node *node; ++ ++ /* The filesystem this directory is in. */ ++ struct procfs *fs; ++ ++ /* The path to this directory in the filesystem. */ ++ const char *fs_path; ++ ++ time_t stat_timestamp; ++ time_t name_timestamp; ++ ++}; ++ ++ ++/* libnetfs node structure */ ++struct netnode ++{ ++ /* Name of this node */ ++ char *name; ++ ++ /* The path in the filesystem that corresponds ++ this node. */ ++ char *fs_path; ++ ++ /* The directory entry for this node. */ ++ struct procfs_dir_entry *dir_entry; ++ ++ /* The proc filesystem */ ++ struct procfs *fs; ++ ++ /* inode number, assigned to this netnode structure. */ ++ unsigned int inode_num; ++ ++ /* If this is a directory, the contents, or 0 if not fetched. */ ++ struct procfs_dir *dir; ++ ++ /* pointer to node structure, assigned to this node. */ ++ struct node *node; ++ ++ /* links to the previous and next nodes in the list */ ++ struct netnode *nextnode, *prevnode; ++ ++ /* link to parent netnode of this file or directory */ ++ struct netnode *parent; ++ ++ /* link to the first child netnode of this directory */ ++ struct netnode *child_first; ++}; ++ ++/* The actual procfs filesystem structure */ ++struct procfs ++{ ++ /* Root of the filesystem. */ ++ struct node *root; ++ ++ /* Inode numbers are assigned sequentially in order of creation. */ ++ ino_t next_inode; ++ int fsid; ++ ++ /* A hash table mapping inode numbers to directory entries. */ ++ struct hurd_ihash inode_mappings; ++ spin_lock_t inode_mappings_lock; ++}; ++ ++extern struct procfs *procfs; ++ ++extern volatile struct mapped_time_value *procfs_maptime; ++ ++extern struct ps_context *ps_context; ++ ++/* Create a new procfs filesystem. */ ++error_t procfs_create (char *procfs_root, int fsid, ++ struct procfs **fs); ++ ++/* Initialize the procfs filesystem for use. */ ++error_t procfs_init (); ++ ++/* Refresh stat information for NODE */ ++error_t procfs_refresh_node (struct node *node); ++ ++/* Return a new node in NODE, with a name NAME, ++ and return the new node with a single ++ reference in NODE. */ ++error_t procfs_create_node (struct procfs_dir_entry *dir_entry, ++ const char *fs_path, ++ struct node **node); ++ ++/* Remove NODE from its entry */ ++error_t procfs_remove_node (struct node *node); ++ ++/* Return in DIR a new procfs directory, in the filesystem FS, ++ with node NODE and path PATH. */ ++error_t procfs_dir_create (struct procfs *fs, struct node *node, ++ const char *path, struct procfs_dir **dir); ++ ++/* Remove the specified DIR and free all its allocated ++ storage. */ ++void procfs_dir_remove (struct procfs_dir *dir); ++ ++/* Refresh DIR. */ ++error_t procfs_dir_refresh (struct procfs_dir *dir, int isroot); ++ ++/* Lookup NAME in DIR, returning its entry, or an error. ++ *NODE will contain the result node, locked, and with ++ an additional reference, or 0 if an error occurs. */ ++error_t procfs_dir_lookup (struct procfs_dir *dir, const char *name, ++ struct node **node); ++ ++#endif /* __PROCFS_H__ */ +--- /dev/null ++++ b/procfs/procfs_dir.c +@@ -0,0 +1,664 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs_dir.c -- This file contains definitions to perform ++ directory operations such as creating, ++ removing and refreshing directories. ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++ ++ A portion of the code in this file is based on ftpfs code ++ present in the hurd repositories copyrighted to FSF. The ++ Copyright notice from that file is given below. ++ ++ Copyright (C) 1997,98,2002 Free Software Foundation, Inc. ++ Written by Miles Bader <miles@gnu.org> ++ This file is part of the GNU Hurd. ++*/ ++ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <hurd/netfs.h> ++#include <hurd/ihash.h> ++#include <sys/stat.h> ++ ++#include "procfs.h" ++ ++/* Initial HASHTABLE length for the new directories to be created. */ ++#define INIT_HTABLE_LEN 5 ++ ++struct procfs_dir_entry **cur_entry; ++ ++/* Return in DIR a new procfs directory, in the filesystem FS, ++ with node NODE and path PATH. */ ++error_t procfs_dir_create (struct procfs *fs, struct node *node, ++ const char *path, struct procfs_dir **dir) ++{ ++ struct procfs_dir *new = malloc (sizeof (struct procfs_dir)); ++ if (!new) ++ return ENOMEM; ++ struct procfs_dir_entry **htable = calloc (INIT_HTABLE_LEN, ++ sizeof (struct procfs_dir_entry *)); ++ if (!htable) ++ return ENOMEM; ++ ++ /* Hold a reference to the new dir's node. */ ++ spin_lock (&netfs_node_refcnt_lock); ++ node->references++; ++ spin_unlock (&netfs_node_refcnt_lock); ++ ++ new->num_entries = 0; ++ new->num_live_entries = 0; ++ new->htable_len = INIT_HTABLE_LEN; ++ new->htable = htable; ++ new->ordered = NULL; ++ new->fs_path = path; ++ new->fs = fs; ++ new->node = node; ++ new->stat_timestamp = 0; ++ new->name_timestamp = 0; ++ ++ *dir = new; ++ ++ if (fs->root != 0) ++ node->nn->dir = new; ++ ++ return 0; ++} ++ ++/* Put the directory entry DIR_ENTRY into the hash table HTABLE. */ ++static void ++insert (struct procfs_dir_entry *dir_entry, ++ struct procfs_dir_entry **htable, size_t htable_len) ++{ ++ struct procfs_dir_entry **new_htable = &htable[dir_entry->hv % htable_len]; ++ if (*new_htable) ++ (*new_htable)->self_p = &dir_entry->next; ++ dir_entry->next = *new_htable; ++ dir_entry->self_p = new_htable; ++ *new_htable = dir_entry; ++} ++ ++/* Calculate NAME's hash value. */ ++static size_t ++hash (const char *name) ++{ ++ size_t hash_value = 0; ++ while (*name) ++ hash_value = ((hash_value << 5) + *name++) & 0xFFFFFF; ++ return hash_value; ++} ++ ++/* Extend the existing hashtable for DIR to accomodate values for new length ++ NEW_LEN. We retain all the previous entries. */ ++static error_t ++rehash (struct procfs_dir *dir, size_t new_len) ++{ ++ int count; ++ size_t old_len = dir->htable_len; ++ struct procfs_dir_entry **old_htable = dir->htable; ++ struct procfs_dir_entry **new_htable = (struct procfs_dir_entry **) ++ malloc (new_len * sizeof (struct procfs_dir_entry *)); ++ ++ if (! new_htable) ++ return ENOMEM; ++ ++ bzero (new_htable, new_len * sizeof (struct procfs_dir_entry *)); ++ ++ for (count = 0; count < old_len; count++) ++ while (old_htable[count]) ++ { ++ struct procfs_dir_entry *dir_entry = old_htable[count]; ++ ++ /* Remove DIR_ENTRY from the old table */ ++ old_htable[count] = dir_entry->next; ++ ++ insert (dir_entry, new_htable, new_len); ++ } ++ ++ free (old_htable); ++ ++ dir->htable = new_htable; ++ dir->htable_len = new_len; ++ ++ return 0; ++} ++ ++/* Lookup NAME in DIR and return its entry. If there is no such entry, and ++ DNEW, the decision variable, is true, then a new entry is allocated and ++ returned, otherwise 0 is returned (if DNEW is true then 0 can be returned ++ if a memory allocation error occurs). */ ++struct procfs_dir_entry * ++lookup_entry (struct procfs_dir *dir, const char *name, int dnew) ++{ ++ size_t hv = hash (name); ++ struct procfs_dir_entry *dir_entry = dir->htable[hv % dir->htable_len]; ++ ++ while (dir_entry && strcmp (name, dir_entry->name) != 0) ++ dir_entry = dir_entry->next; ++ ++ if (!dir_entry && dnew) ++ { ++ if (dir->num_entries > dir->htable_len) ++ /* Grow the hash table. */ ++ if (rehash (dir, (dir->htable_len + 1) * 2 - 1) != 0) ++ return 0; ++ ++ dir_entry = ++ (struct procfs_dir_entry *) malloc (sizeof (struct procfs_dir_entry)); ++ ++ if (dir_entry) ++ { ++ dir_entry->hv = hv; ++ dir_entry->name = strdup (name); ++ dir_entry->node = 0; ++ dir_entry->dir = dir; ++ dir_entry->stat_timestamp = 0; ++ bzero (&dir_entry->stat, sizeof dir_entry->stat); ++ dir_entry->symlink_target = 0; ++ dir_entry->noent = 0; ++ dir_entry->valid = 0; ++ dir_entry->name_timestamp = 0; ++ dir_entry->ordered_next = 0; ++ dir_entry->ordered_self_p = 0; ++ dir_entry->next = 0; ++ dir_entry->self_p = 0; ++ insert (dir_entry, dir->htable, dir->htable_len); ++ dir->num_entries++; ++ } ++ } ++ ++ return dir_entry; ++} ++ ++ ++/* Lookup NAME in DIR, returning its entry, or an error. ++ *NODE will contain the result node, locked, and with ++ an additional reference, or 0 if an error occurs. */ ++error_t procfs_dir_lookup (struct procfs_dir *dir, const char *name, ++ struct node **node) ++{ ++ struct procfs_dir_entry *dir_entry = 0; ++ error_t err = 0; ++ char *fs_path = dir->fs_path; ++ ++ struct timeval tv; ++ maptime_read (procfs_maptime, &tv); ++ ++ time_t timestamp = tv.tv_sec; ++ ++ if (*name == '\0' || strcmp (name, ".") == 0) ++ /* Current directory -- just add an additional reference to DIR's node ++ and return it. */ ++ { ++ netfs_nref (dir->node); ++ *node = dir->node; ++ return 0; ++ } ++ else if (strcmp (name, "..") == 0) ++ /* Parent directory. */ ++ { ++ if (dir->node->nn->dir_entry) ++ { ++ *node = dir->node->nn->dir_entry->dir->node; ++ mutex_lock (&(*node)->lock); ++ netfs_nref (*node); ++ } ++ else ++ { ++ err = ENOENT; /* No .. */ ++ *node = 0; ++ } ++ ++ mutex_unlock (&dir->node->lock); ++ ++ return err; ++ } ++ ++ err = procfs_dir_refresh (dir, dir->node == dir->fs->root); ++ if (!err && !dir_entry) ++ dir_entry = lookup_entry (dir, name, 0); ++ ++ if (! err) ++ { ++ if (dir_entry && !dir_entry->noent) ++ /* We've got a dir entry, get a node for it. */ ++ { ++ /* If there's already a node, add a ref so that it doesn't go ++ away. */ ++ spin_lock (&netfs_node_refcnt_lock); ++ if (dir_entry->node) ++ dir_entry->node->references++; ++ spin_unlock (&netfs_node_refcnt_lock); ++ ++ if (! dir_entry->node) ++ /* No node; make one and install it into E. */ ++ { ++ if (! fs_path) ++ err = EROFS; ++ ++ if (! err) ++ { ++ err = procfs_create_node (dir_entry, fs_path, &dir_entry->node); ++ ++ if (!err && dir->num_live_entries++ == 0) ++ /* Keep a reference to dir's node corresponding to ++ children. */ ++ { ++ spin_lock (&netfs_node_refcnt_lock); ++ dir->node->references++; ++ spin_unlock (&netfs_node_refcnt_lock); ++ } ++ } ++ } ++ ++ if (! err) ++ { ++ *node = dir_entry->node; ++ /* We have to unlock DIR's node before locking the child node ++ because the locking order is always child-parent. We know ++ the child node won't go away because we already hold the ++ additional reference to it. */ ++ mutex_unlock (&dir->node->lock); ++ mutex_lock (&dir_entry->node->lock); ++ } ++ } ++ else ++ err = ENOENT; ++ } ++ ++ if (err) ++ { ++ *node = 0; ++ mutex_unlock (&dir->node->lock); ++ } ++ ++#if 0 ++ if (fs_path) ++ free (fs_path); ++#endif ++ ++ return err; ++} ++ ++/* Lookup the null name in DIR, and return a node for it in NODE. Unlike ++ procfs_dir_lookup, this won't attempt to validate the existance of the ++ entry (to avoid opening a new connection if possible) -- that will happen ++ the first time the entry is refreshed. Also unlink ftpfs_dir_lookup, this ++ function doesn't expect DIR to be locked, and won't return *NODE locked. ++ This function is only used for bootstrapping the root node. */ ++error_t ++procfs_dir_null_lookup (struct procfs_dir *dir, struct node **node) ++{ ++ struct procfs_dir_entry *dir_entry; ++ error_t err = 0; ++ ++ dir_entry = lookup_entry (dir, "", 1); ++ if (! dir_entry) ++ return ENOMEM; ++ ++ if (! dir_entry->noent) ++ /* We've got a dir entry, get a node for it. */ ++ { ++ /* If there's already a node, add a ref so that it doesn't go away. */ ++ spin_lock (&netfs_node_refcnt_lock); ++ if (dir_entry->node) ++ dir_entry->node->references++; ++ spin_unlock (&netfs_node_refcnt_lock); ++ ++ if (! dir_entry->node) ++ /* No node; make one and install it into DIR_ENTRY. */ ++ { ++ err = procfs_create_node (dir_entry, dir->fs_path, &dir_entry->node); ++ ++ if (!err && dir->num_live_entries++ == 0) ++ /* Keep a reference to dir's node corresponding to children. */ ++ { ++ spin_lock (&netfs_node_refcnt_lock); ++ dir->node->references++; ++ spin_unlock (&netfs_node_refcnt_lock); ++ } ++ } ++ ++ if (! err) ++ *node = dir_entry->node; ++ } ++ else ++ err = ENOENT; ++ ++ return err; ++} ++ ++/* Free the directory entry DIR_ENTRY and all resources it consumes. */ ++void ++free_entry (struct procfs_dir_entry *dir_entry) ++{ ++ ++ assert (! dir_entry->self_p); /* We should only free deleted nodes. */ ++ free (dir_entry->name); ++ if (dir_entry->symlink_target) ++ free (dir_entry->symlink_target); ++ free (dir_entry->node->nn->dir); ++ free (dir_entry->node->nn); ++ free (dir_entry->node); ++ free (dir_entry); ++} ++ ++/* Remove DIR_ENTRY from its position in the ordered_next chain. */ ++static void ++ordered_unlink (struct procfs_dir_entry *dir_entry) ++{ ++ if (dir_entry->ordered_self_p) ++ *dir_entry->ordered_self_p = dir_entry->ordered_next; ++ if (dir_entry->ordered_next) ++ dir_entry->ordered_next->self_p = dir_entry->ordered_self_p; ++} ++ ++/* Delete DIR_ENTRY from its directory, freeing any resources it holds. */ ++static void ++delete (struct procfs_dir_entry *dir_entry, struct procfs_dir *dir) ++{ ++ dir->num_entries--; ++ ++ /* Take out of the hash chain. */ ++ if (dir_entry->self_p) ++ *dir_entry->self_p = dir_entry->next; ++ if (dir_entry->next) ++ dir_entry->next->self_p = dir_entry->self_p; ++ ++ /* Take out of the directory ordered list. */ ++ ordered_unlink (dir_entry); ++ ++ /* If there's a node attached, we'll delete the entry whenever it goes ++ away, otherwise, just delete it now. */ ++ if (! dir_entry->node) ++ free_entry (dir_entry); ++} ++ ++/* Make all the directory entries invalid */ ++static void ++make_dir_invalid (struct procfs_dir *dir) ++{ ++ int count; ++ size_t len = dir->htable_len; ++ struct procfs_dir_entry **htable = dir->htable; ++ struct procfs_dir_entry *dir_entry; ++ ++ for (count = 0; count < len; count++) ++ { ++ dir_entry = htable[count]; ++ while (dir_entry) ++ { ++ dir_entry->valid = 0; ++ dir_entry = dir_entry->next; ++ } ++ } ++} ++ ++/* Delete any entries in DIR which don't have their valid bit set. */ ++static void ++sweep (struct procfs_dir *dir) ++{ ++ size_t len = dir->htable_len, i; ++ struct procfs_dir_entry **htable = dir->htable, *dir_entry; ++ ++ for (i = 0; i < len; i++) ++ { ++ dir_entry = htable[i]; ++ while (dir_entry) ++ { ++ if (!dir_entry->valid && !dir_entry->noent && dir->num_entries) ++ delete (dir_entry, dir); ++ dir_entry = dir_entry->next; ++ } ++ if (htable[i]) ++ { ++ free (htable[i]); ++ htable[i] = 0; ++ } ++ ++ } ++ ++} ++ ++/* Remove the specified DIR and free all its allocated ++ storage. */ ++void procfs_dir_entries_remove (struct procfs_dir *dir) ++{ ++ /* Free all entries. */ ++ make_dir_invalid (dir); ++ sweep (dir); ++} ++ ++/* Checks if the DIR name is in list of ++ Active pids. */ ++int is_in_pid_list (struct procfs_dir *dir) ++{ ++ int dir_name; ++ int count; ++ pid_t *pids = NULL; ++ int pidslen = 0; ++ error_t err; ++ ++ if (dir->node->nn) ++ { ++ dir_name = atoi (dir->node->nn->dir_entry->name); ++ err = proc_getallpids (getproc (), &pids, &pidslen); ++ ++ for (count = 0; count < pidslen; ++count) ++ if (pids[count] == dir_name) ++ return 1; ++ } ++ ++ return 0; ++ ++} ++ ++/* Checks if DIR is a directory that ++ represents a pid. */ ++int check_parent (struct procfs_dir *dir) ++{ ++ if (dir == dir->fs->root) ++ return 0; ++ else ++ if (is_in_pid_list (dir)) ++ return 1; ++ else ++ return 0; ++ ++} ++ ++/* Refresh DIR. */ ++error_t procfs_dir_refresh (struct procfs_dir *dir, int isroot) ++{ ++ error_t err; ++ int is_parent_pid; ++ struct node *node; ++ ++ struct timeval tv; ++ maptime_read (procfs_maptime, &tv); ++ ++ time_t timestamp = tv.tv_sec; ++ cur_entry = &dir->ordered; ++ if (isroot) ++ err = procfs_fill_root_dir(dir, timestamp); ++ else ++ { ++ err = update_dir_entries (dir, timestamp); ++ is_parent_pid = check_parent (dir); ++ if (is_parent_pid) ++ err = procfs_create_files (dir, &node, timestamp); ++ } ++ ++ return err; ++} ++ ++/* Update the directory entry for NAME to reflect STAT and SYMLINK_TARGET. ++ This also creates a valid linked list of entries imposing ordering on ++ them. */ ++struct procfs_dir_entry* ++update_entries_list (struct procfs_dir *dir, const char *name, ++ const struct stat *stat, time_t timestamp, ++ const char *symlink_target) ++{ ++ ino_t ino; ++ struct procfs_dir_entry *dir_entry = lookup_entry (dir, name, 1); ++ struct procfs *fs = dir->fs; ++ ++ if (! dir_entry) ++ return ENOMEM; ++ ++ if (dir_entry->stat.st_ino) ++ ino = dir_entry->stat.st_ino; ++ else ++ ino = fs->next_inode++; ++ ++ dir_entry->name_timestamp = timestamp; ++ ++ if (stat) ++ /* The ST and SYMLINK_TARGET parameters are only valid if ST isn't 0. */ ++ { ++ dir_entry->stat = *stat; ++ dir_entry->stat_timestamp = timestamp; ++ ++ if (!dir_entry->symlink_target || !symlink_target ++ || strcmp (dir_entry->symlink_target, symlink_target) != 0) ++ { ++ if (dir_entry->symlink_target) ++ free (dir_entry->symlink_target); ++ dir_entry->symlink_target = symlink_target ? strdup (symlink_target) : 0; ++ } ++ } ++ ++ /* The st_ino field is always valid. */ ++ dir_entry->stat.st_ino = ino; ++ dir_entry->stat.st_fsid = fs->fsid; ++ dir_entry->stat.st_fstype = PROCFILESYSTEM; ++ ++ dir_entry->valid = 1; ++ ++ if (! dir_entry->ordered_self_p) ++ /* Position DIR_ENTRY in the ordered chain following the previously seen entry. */ ++ { ++ /* The PREV_ENTRY_NEXT_P field holds a pointer to the NEXT-field of the ++ previous entry, or a pointer to the ORDERED field in the directory. */ ++ dir_entry->ordered_self_p = cur_entry; ++ ++ if (*dir_entry->ordered_self_p) ++ /* Update the self_p pointer of the previous successor. */ ++ (*dir_entry->ordered_self_p)->ordered_self_p = &dir_entry->ordered_next; ++ ++ /* DIR_ENTRY comes before the previous successor. */ ++ dir_entry->ordered_next = *dir_entry->ordered_self_p; ++ ++ *dir_entry->ordered_self_p = dir_entry; /* Put DIR_ENTRY there. */ ++ } ++ ++ /* Put the next entry after this one. */ ++ cur_entry = &dir_entry->ordered_next; ++ ++ return dir_entry; ++} ++ ++/* Fills DIR, the root directory with all the pids of ++ processes running in the system as directories. */ ++error_t ++procfs_fill_root_dir(struct procfs_dir *dir, time_t timestamp) ++{ ++ error_t err; ++ char *data; ++ pid_t *pids; ++ int pidslen; ++ struct stat stat; ++ stat.st_mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | ++ S_IROTH | S_IXOTH; ++ stat.st_nlink = 1; ++ stat.st_size = 0; ++ ++ int count; ++ char *dir_name_pid; ++ struct node *node; ++ struct procfs_dir *new_dir; ++ struct procfs_dir_entry *dir_entry; ++ struct proc_stat *ps; ++ ++ pids = NULL; ++ pidslen = 0; ++ err = proc_getallpids (getproc (), &pids, &pidslen); ++ ++ if (!err) ++ { ++ for (count = 0; count < pidslen; count++) ++ { ++ if (asprintf (&dir_name_pid, "%d", pids[count]) == -1) ++ return errno; ++ ++#if 0 ++ node = (struct node *) malloc (sizeof (struct node)); ++ new_dir = (struct procfs_dir *) malloc (sizeof (struct procfs_dir )); ++ ++ if (! node || ! new_dir ) ++ return ENOMEM; ++#endif ++ err = _proc_stat_create (pids[count], ps_context, &ps); ++ if (! err) ++ { ++ err = set_field_value (ps, PSTAT_PROC_INFO); ++ if (! err) ++ { ++ stat.st_uid = proc_stat_proc_info (ps)->owner; ++ stat.st_gid = proc_stat_proc_info (ps)->pgrp; ++ ++ dir_entry = update_entries_list (dir, dir_name_pid, ++ &stat, timestamp, NULL); ++ err = procfs_create_node (dir_entry, dir_name_pid, &node); ++ ++ procfs_dir_create (dir->fs, node, ++ dir_name_pid, &new_dir); ++ } ++ _proc_stat_free (ps); ++ } ++ free(dir_name_pid); ++ } ++ } ++ ++ if ((err = procfs_create_uptime (dir, &node, timestamp)) != 0) ++ return err; ++ ++ if ((err = procfs_create_stat (dir, &node, timestamp)) != 0) ++ return err; ++ ++ if ((err = procfs_create_version (dir, &node, timestamp)) != 0) ++ return err; ++ ++ if ((err = procfs_create_meminfo (dir, &node, timestamp)) != 0) ++ return err; ++ ++ if ((err = procfs_create_loadavg (dir, &node, timestamp)) != 0) ++ return err; ++ ++ return 0; ++} ++ ++error_t update_dir_entries (struct procfs_dir *dir) ++{ ++ /* STUB */ ++ return 0; ++} +--- /dev/null ++++ b/procfs/procfs_nonpid_files.c +@@ -0,0 +1,514 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs_nonpid_files.c -- This file contains function definitions ++ to create and update the non-Per PID ++ files and their contents. ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++ ++ A portion of the code in this file is based on vmstat.c code ++ present in the hurd repositories copyrighted to FSF. The ++ Copyright notice from that file is given below. ++ ++ Copyright (C) 1997,98,2002 Free Software Foundation, Inc. ++ Written by Miles Bader <miles@gnu.org> ++ This file is part of the GNU Hurd. ++*/ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <hurd/netfs.h> ++#include <hurd/ihash.h> ++#include <fcntl.h> ++#include <sys/stat.h> ++#include <sys/sysinfo.h> ++#include <mach/vm_statistics.h> ++#include <mach/default_pager.h> ++#include <hurd.h> ++#include <hurd/paths.h> ++#include <mach.h> ++#include <ps.h> ++#include <time.h> ++ ++#include "procfs.h" ++ ++typedef long long val_t; ++#define BADVAL ((val_t) - 1LL) ++ ++/* default pager port (must be privileged to fetch this). */ ++mach_port_t def_pager; ++struct default_pager_info def_pager_info; ++ ++error_t procfs_create_uptime (struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "uptime") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s", "uptime") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ return err; ++} ++ ++error_t procfs_create_version(struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "version") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s", "version") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ return 0; ++} ++ ++error_t procfs_create_stat (struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "stat") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s", "stat") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ return err; ++} ++ ++error_t procfs_create_meminfo (struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "meminfo") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s", "meminfo") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ return err; ++} ++ ++error_t procfs_create_loadavg (struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "loadavg") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s", "loadavg") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ return err; ++} ++ ++error_t get_uptime (struct timeval *uptime) ++{ ++ struct timeval boot_time, now; ++ error_t err; ++ struct proc_stat *ps; ++ ++ err = _proc_stat_create (1, ps_context, &ps); ++ ++ if (err) ++ return err; ++ ++ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); ++ if (!err && !(ps->flags & PSTAT_TASK_BASIC)) ++ err = EGRATUITOUS; ++ ++ if (! err) ++ { ++ time_value_t *const tv = &proc_stat_task_basic_info (ps)->creation_time; ++ boot_time.tv_sec = tv->seconds; ++ boot_time.tv_usec = tv->microseconds; ++ if (gettimeofday (&now, 0) < 0) ++ error (0, errno, "gettimeofday"); ++ timersub (&now, &boot_time, uptime); ++ } ++ ++ _proc_stat_free (ps); ++ return err; ++} ++ ++error_t get_total_times (struct timeval *total_user_time, ++ struct timeval *total_system_time) ++{ ++ error_t err; ++ pid_t *pids; ++ int pidslen = 0, count; ++ struct proc_stat *ps; ++ struct task_thread_times_info live_threads_times; ++ ++ struct timeval total_user_time_tmp; ++ struct timeval total_system_time_tmp; ++ struct timeval tmpval; ++ ++ timerclear (&total_user_time_tmp); ++ timerclear (&total_system_time_tmp); ++ ++ pids = NULL; ++ err = proc_getallpids (getproc (), &pids, &pidslen); ++ ++ if (!err) ++ for (count = 0; count < pidslen; count++) ++ { ++ err = _proc_stat_create (pids[count], ps_context, &ps); ++ if (err) ++ return err; ++ ++ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); ++ if (!err && !(ps->flags & PSTAT_TASK_BASIC)) ++ err = EGRATUITOUS; ++ ++ if (! err) ++ { ++ tmpval.tv_sec = proc_stat_task_basic_info (ps)->user_time.seconds; ++ tmpval.tv_usec = proc_stat_task_basic_info (ps)->user_time.seconds; ++ timeradd (&total_user_time_tmp, &tmpval, &total_user_time_tmp); ++ ++ tmpval.tv_sec = proc_stat_task_basic_info (ps)->system_time.seconds; ++ tmpval.tv_usec = proc_stat_task_basic_info (ps)->system_time.seconds; ++ timeradd (&total_system_time_tmp, &tmpval, &total_system_time_tmp); ++ ++ error_t err = set_field_value (ps, PSTAT_TASK); ++ if (! err) ++ { ++ err = get_task_thread_times (ps->task, &live_threads_times); ++ if (! err) ++ { ++ tmpval.tv_sec = live_threads_times.user_time.seconds; ++ tmpval.tv_usec = live_threads_times.user_time.microseconds; ++ timeradd (&total_user_time_tmp, &tmpval, &total_user_time_tmp); ++ ++ tmpval.tv_sec = live_threads_times.system_time.seconds; ++ tmpval.tv_usec = live_threads_times.system_time.microseconds; ++ timeradd (&total_system_time_tmp, &tmpval, &total_system_time_tmp); ++ } ++ } ++ } ++ _proc_stat_free (ps); ++ } ++ ++ total_user_time->tv_sec = total_user_time_tmp.tv_sec; ++ total_user_time->tv_usec = total_user_time_tmp.tv_usec; ++ ++ total_system_time->tv_sec = total_system_time_tmp.tv_sec; ++ total_system_time->tv_usec = total_system_time_tmp.tv_usec; ++ ++ return err; ++} ++ ++error_t procfs_read_nonpid_stat (struct dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *stat_data; ++ error_t err; ++ jiffy_t total_user_time_jiffy, total_system_time_jiffy; ++ jiffy_t idle_time_jiffy; ++ struct timeval uptime, total_user_time, total_system_time; ++ struct timeval idle_time; ++ ++ err = get_uptime (&uptime); ++ ++ if (! err) ++ { ++ err = get_total_times (&total_user_time, &total_system_time); ++ ++ if (! err) ++ { ++ timersub (&uptime, &total_system_time, ++ &idle_time); ++ ++ total_user_time_jiffy = 100 * ((double) total_user_time.tv_sec + ++ (double) total_user_time.tv_usec / (1000 * 1000)); ++ total_system_time_jiffy = 100 * ((double) total_system_time.tv_sec + ++ (double) total_system_time.tv_usec / (1000 * 1000)); ++ idle_time_jiffy = 100 * ((double) idle_time.tv_sec + ++ (double) idle_time.tv_usec / (1000 * 1000)); ++ ++ if (asprintf (&stat_data, "cpu %llu %llu %llu %llu %llu %llu %d %d %d\n" ++ "cpu0 %llu %llu %llu %llu %llu %llu %d %d %d\n" ++ "intr %llu %llu %llu %llu %llu %llu %d %d %d\n", ++ total_user_time_jiffy, (long long unsigned) 0, ++ total_system_time_jiffy, idle_time_jiffy, ++ (long long unsigned) 0, (long long unsigned) 0, ++ 0, 0, 0, ++ total_user_time_jiffy, (long long unsigned) 0, ++ total_system_time_jiffy, idle_time_jiffy, ++ (long long unsigned) 0, (long long unsigned) 0, ++ 0, 0, 0, ++ (long long unsigned) 0, ++ (long long unsigned) 0, (long long unsigned) 0, (long long unsigned) 0, ++ (long long unsigned) 0, ++ (long long unsigned) 0, (long long unsigned) 0, ++ (long long unsigned) 0, (long long unsigned) 0) == -1) ++ return errno; ++ } ++ } ++ ++ memcpy (data, stat_data, strlen(stat_data)); ++ *len = strlen (data); ++ ++ free (stat_data); ++ return err; ++} ++ ++/* Makes sure the default pager port and associated ++ info exists, and returns 0 if not (after printing ++ an error). */ ++static int ++ensure_def_pager_info () ++{ ++ error_t err; ++ ++ if (def_pager == MACH_PORT_NULL) ++ { ++ mach_port_t host; ++ ++ err = get_privileged_ports (&host, 0); ++ if (err == EPERM) ++ { ++ /* We are not root, so try opening the /servers file. */ ++ def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0); ++ if (def_pager == MACH_PORT_NULL) ++ { ++ error (0, errno, _SERVERS_DEFPAGER); ++ return 0; ++ } ++ } ++ if (def_pager == MACH_PORT_NULL) ++ { ++ if (err) ++ { ++ error (0, err, "get_privileged_ports"); ++ return 0; ++ } ++ ++ err = vm_set_default_memory_manager (host, &def_pager); ++ mach_port_deallocate (mach_task_self (), host); ++ ++ if (err) ++ { ++ error (0, err, "vm_set_default_memory_manager"); ++ return 0; ++ } ++ } ++ } ++ ++ if (!MACH_PORT_VALID (def_pager)) ++ { ++ if (def_pager == MACH_PORT_NULL) ++ { ++ error (0, 0, ++ "No default pager running, so no swap information available"); ++ def_pager = MACH_PORT_DEAD; /* so we don't try again */ ++ } ++ return 0; ++ } ++ ++ err = default_pager_info (def_pager, &def_pager_info); ++ if (err) ++ error (0, err, "default_pager_info"); ++ return (err == 0); ++} ++ ++#define SWAP_FIELD(getter, expr) \ ++ static val_t getter () \ ++ { return ensure_def_pager_info () ? (val_t) (expr) : BADVAL; } ++ ++SWAP_FIELD (get_swap_size, def_pager_info.dpi_total_space) ++SWAP_FIELD (get_swap_free, def_pager_info.dpi_free_space) ++SWAP_FIELD (get_swap_page_size, def_pager_info.dpi_page_size) ++SWAP_FIELD (get_swap_active, (def_pager_info.dpi_total_space ++ - def_pager_info.dpi_free_space)) ++ ++error_t procfs_read_nonpid_meminfo (struct dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *meminfo_data; ++ error_t err; ++ struct vm_statistics vmstats; ++ ++ err = vm_statistics (mach_task_self (), &vmstats); ++ ++ unsigned long mem_size = ((vmstats.free_count + ++ vmstats.active_count + vmstats.inactive_count + ++ vmstats.wire_count) * vmstats.pagesize) / 1024; ++ ++ if (! err) ++ if (asprintf (&meminfo_data, "MemTotal:\t%lu kB\n" ++ "MemFree:\t%lu kB\n" ++ "Buffers:\t%ld kB\n" ++ "Cached:\t\t%ld kB\n" ++ "SwapCached:\t%ld kB\n" ++ "Active:\t\t%lu kB\n" ++ "Inactive:\t%lu kB\n" ++ "HighTotal:\t%lu kB\n" ++ "HighFree:\t%lu kB\n" ++ "LowTotal:\t%lu kB\n" ++ "LowFree:\t%lu kB\n" ++ "SwapTotal:\t%llu kB\n" ++ "SwapFree:\t%llu kB\n", ++ mem_size, (PAGES_TO_BYTES(vmstats.free_count)) / 1024 , 0, 0, 0, ++ (PAGES_TO_BYTES(vmstats.active_count)) / 1024, ++ (PAGES_TO_BYTES(vmstats.inactive_count)) / 1024, 0, 0, 0, 0, ++ get_swap_size () / 1024, get_swap_free () / 1024) == -1) ++ return errno; ++ ++ memcpy (data, meminfo_data, strlen(meminfo_data)); ++ *len = strlen (data); ++ ++ free (meminfo_data); ++ return err; ++} ++ ++error_t procfs_read_nonpid_loadavg (struct dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *loadavg_data; ++ error_t err; ++ processor_set_info_t info; ++ natural_t *count; ++ struct host_load_info *load; ++ mach_port_t host; ++ ++ err = ps_host_load_info (&load); ++ if (err) ++ error (0, err, "ps_host_load_info"); ++ ++ if (! err) ++ if (asprintf (&loadavg_data, "%.2f %.2f %.2f %d/%d %d\n", ++ (double)load->avenrun[0] / (double)LOAD_SCALE, ++ (double)load->avenrun[1] / (double)LOAD_SCALE, ++ (double)load->avenrun[2] / (double)LOAD_SCALE, 0, 0, 0) == -1) ++ return errno; ++ ++ memcpy (data, loadavg_data, strlen(loadavg_data)); ++ *len = strlen (data); ++ ++ free (loadavg_data); ++ return err; ++} ++ ++error_t procfs_read_nonpid_uptime (struct dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *uptime_data; ++ error_t err; ++ double uptime_secs, idle_time_secs; ++ ++ struct timeval uptime_val; ++ struct timeval uptime, total_user_time, total_system_time; ++ struct timeval idle_time; ++ ++ ++ err = get_uptime (&uptime); ++ if (! err) ++ { ++ err = get_total_times (&total_user_time, ++ &total_system_time); ++ if (! err) ++ { ++ timersub (&uptime, &total_system_time, ++ &idle_time); ++ ++ uptime_secs = (double) uptime.tv_sec + ++ (double) uptime.tv_usec / (1000 * 1000); ++ ++ idle_time_secs = (double) idle_time.tv_sec + ++ (double) idle_time.tv_usec / (1000 * 1000); ++ ++ if (asprintf (&uptime_data, "%.2f %.2f\n", ++ uptime_secs, idle_time_secs) == -1) ++ return errno; ++ } ++ } ++ ++ ++ memcpy (data, uptime_data, strlen(uptime_data)); ++ *len = strlen (data); ++ ++ free (uptime_data); ++ return err; ++} ++ ++error_t procfs_read_nonpid_version (struct dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *version_data; ++ error_t err = 0; ++ ++ if (asprintf (&version_data, "Linux version 2.6.18\n", NULL) == -1) ++ return errno; ++ ++ memcpy (data, version_data, strlen(version_data)); ++ *len = strlen (data); ++ ++ free (version_data); ++ return err; ++} +--- /dev/null ++++ b/procfs/procfs_pid.h +@@ -0,0 +1,88 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs_pid.h -- This is the header file of which contains defintions ++ for structure of directory with PID as the name and ++ structure of each file in this directory. ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++*/ ++ ++#ifndef __PROCFS_PID_H__ ++#define __PROCFS_PID_H__ ++ ++#include "procfs.h" ++ ++struct procfs_pid_files ++{ ++ struct procfs_cwd *procfs_cwd; ++ struct procfs_environ *procfs_environ; ++ struct procfs_cpu *procfs_cpu; ++ struct procfs_root *procfs_root; ++ struct procfs_exe *procfs_exe; ++ struct procfs_stat *_procfs_stat; ++ struct procfs_statm *procfs_statm; ++}; ++ ++struct procfs_stat ++{ ++ pid_t pid; ++ char *comm; ++ char *state; ++ pid_t ppid; ++ pid_t pgid; ++ pid_t sid; ++ int tty_nr; ++ pid_t tty_pgrp; ++ unsigned flags; ++ long unsigned minflt; ++ long unsigned cminflt; ++ long unsigned majflt; ++ long unsigned cmajflt; ++ jiffy_t utime; ++ jiffy_t stime; ++ jiffy_t cutime; ++ jiffy_t cstime; ++ long priority; ++ long nice; ++ long num_threads; ++ long itrealvalue; ++ long long unsigned starttime; ++ long unsigned vsize; ++ long rss; ++ long unsigned rlim; ++ long unsigned startcode; ++ long unsigned endcode; ++ long unsigned startstack; ++ long unsigned kstkesp; ++ long unsigned kstkeip; ++ long unsigned signal; ++ long unsigned blocked; ++ long unsigned sigignore; ++ long unsigned sigcatch; ++ long unsigned wchan; ++ long unsigned nswap; ++ long unsigned cnswap; ++ int exit_signal; ++ int processor; ++ unsigned rt_priority; ++ unsigned policy; ++ long long unsigned delayacct_blkio_ticks; ++}; ++ ++#endif +--- /dev/null ++++ b/procfs/procfs_pid_files.c +@@ -0,0 +1,576 @@ ++/* procfs -- a translator for providing GNU/Linux compatible ++ proc pseudo-filesystem ++ ++ procfs_pid_files.c -- This file contains definitions to perform ++ file operations such as creating, writing to, ++ reading from and removing files that holds ++ information for each process with PID ++ ++ Copyright (C) 2008, FSF. ++ Written as a Summer of Code Project ++ ++ ++ procfs 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. ++ ++ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++ ++ A portion of the code in this file is based on ftpfs code ++ present in the hurd repositories copyrighted to FSF. The ++ Copyright notice from that file is given below. ++ ++*/ ++ ++#include <hurd/netfs.h> ++#include <fcntl.h> ++#include <string.h> ++#include <stdio.h> ++#include <mach/task_info.h> ++#include <sys/resource.h> ++ ++#include "procfs_pid.h" ++ ++/* Update the files named NAME within the directory named ++ PID also with SYMLINK TARGET if necessary. */ ++struct procfs_dir_entry* ++update_pid_entries (struct procfs_dir *dir, const char *name, ++ time_t timestamp, ++ const char *symlink_target) ++{ ++ struct procfs_dir_entry *dir_entry; ++ struct stat stat = {}; ++ stat.st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; ++ ++ dir_entry = update_entries_list (dir, name, &stat, ++ timestamp, symlink_target); ++ ++ return dir_entry; ++} ++ ++/* Creates files to store process information for DIR ++ whose names are pids and returns these files in *NODE. */ ++error_t ++procfs_create_files (struct procfs_dir *dir, ++ struct node **node, ++ time_t timestamp) ++{ ++ int err; ++ char *file_name, *file_path; ++ struct procfs_dir_entry *dir_entry; ++ ++ if (asprintf (&file_name, "%s", "stat") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s/%s", dir->node->nn->dir_entry->name, "stat") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ if (asprintf (&file_name, "%s", "status") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s/%s", dir->node->nn->dir_entry->name, "status") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ if (asprintf (&file_name, "%s", "cmdline") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s/%s", dir->node->nn->dir_entry->name, "cmdline") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++ if (asprintf (&file_name, "%s", "statm") == -1) ++ return errno; ++ if (asprintf (&file_path, "%s/%s", dir->node->nn->dir_entry->name, "statm") == -1) ++ return errno; ++ ++ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL); ++ err = procfs_create_node (dir_entry, file_path, node); ++ ++ free (file_name); ++ free (file_path); ++ ++#if 0 ++ nodes_list = &node_stat; ++ nodes_list++; ++ node = nodes_list; ++#endif ++ ++ return err; ++} ++ ++/* Check if the PSTAT_FLAG is set in the corresponding PS ++ structure, if not set it and check again and return error ++ status accordingly. */ ++error_t set_field_value (struct proc_stat *ps, int pstat_flag) ++{ ++ error_t err; ++ ++ if (! (ps->flags & pstat_flag)) ++ { ++ err = proc_stat_set_flags (ps, pstat_flag); ++ if (err) ++ return err; ++ ++ /* This second check is done since ps.h specifies to ++ do so since the previous call would not have set ++ the required value. */ ++ if (! (ps->flags & pstat_flag)) ++ return EGRATUITOUS; ++ } ++ ++ return 0; ++} ++ ++/* Adjusts TIME_VAL structure having Seconds and ++ Microseconds into the value in jiffies. The ++ value of jiffy is a hack to adjust to what ++ procps uses. */ ++jiffy_t adjust_jiffy_time (time_value_t time_val) ++{ ++ jiffy_t jiffy_time = time_val.seconds * JIFFY_ADJUST; ++ jiffy_time += (time_val.microseconds * JIFFY_ADJUST) ++ / (1000 * 1000); ++ ++ return jiffy_time; ++} ++ ++/* Extract the user and system time for the live threads of ++ the process. This information is directly retrieved from ++ MACH since neither libps not proc makes this available. */ ++error_t get_task_thread_times (task_t task, ++ struct task_thread_times_info *live_threads_times) ++{ ++ error_t err; ++ size_t tkcount = TASK_THREAD_TIMES_INFO_COUNT; ++ ++ err = task_info (task, TASK_THREAD_TIMES_INFO, ++ (task_info_t) live_threads_times, &tkcount); ++ if (err == MACH_SEND_INVALID_DEST) ++ err = ESRCH; ++ ++ return err; ++} ++ ++/* Obtains the User Time in UTIME and System Time in STIME from ++ MACH directly since this is neither made available by libps ++ nor by proc server. */ ++error_t get_live_threads_time (struct proc_stat *ps, ++ jiffy_t *utime, jiffy_t *stime) ++{ ++ struct task_thread_times_info live_threads_times; ++ error_t err = set_field_value (ps, PSTAT_TASK); ++ ++ if (! err) ++ { ++ err = get_task_thread_times (ps->task, &live_threads_times); ++ if (! err) ++ { ++ *utime = adjust_jiffy_time ( ++ live_threads_times.user_time); ++ *stime = adjust_jiffy_time ( ++ live_threads_times.system_time); ++ } ++ } ++ ++ return err; ++} ++ ++/* Get the data for stat file into the structure ++ PROCFS_STAT. */ ++error_t get_stat_data (pid_t pid, ++ struct procfs_stat **procfs_stat) ++{ ++ error_t err; ++ struct procfs_stat *new = (struct procfs_stat *) ++ malloc (sizeof (struct procfs_stat)); ++ ++ struct proc_stat *ps; ++ jiffy_t utime, stime; ++ ++ err = _proc_stat_create (pid, ps_context, &ps); ++ ++ new->pid = pid; ++ ++ if (! err) ++ { ++ err = set_field_value (ps, PSTAT_ARGS); ++ if (! err) ++ asprintf (&new->comm, "%s", ps->args); ++ } ++ ++ err = set_field_value (ps, PSTAT_STATE); ++ if (! err) ++ { ++ if (ps->state & PSTAT_STATE_P_STOP) ++ new->state = strdup ("T"); ++ if (ps->state & PSTAT_STATE_P_ZOMBIE) ++ new->state = strdup ("Z"); ++ if (ps->state & PSTAT_STATE_P_FG) ++ new->state = strdup ("+"); ++ if (ps->state & PSTAT_STATE_P_SESSLDR) ++ new->state = strdup ("s"); ++ if (ps->state & PSTAT_STATE_P_LOGINLDR) ++ new->state = strdup ("l"); ++ if (ps->state & PSTAT_STATE_P_FORKED) ++ new->state = strdup ("f"); ++ if (ps->state & PSTAT_STATE_P_NOMSG) ++ new->state = strdup ("m"); ++ if (ps->state & PSTAT_STATE_P_NOPARENT) ++ new->state = strdup ("p"); ++ if (ps->state & PSTAT_STATE_P_ORPHAN) ++ new->state = strdup ("o"); ++ if (ps->state & PSTAT_STATE_P_TRACE) ++ new->state = strdup ("x"); ++ if (ps->state & PSTAT_STATE_P_WAIT) ++ new->state = strdup ("w"); ++ if (ps->state & PSTAT_STATE_P_GETMSG) ++ new->state = strdup ("g"); ++ } ++ ++ err = set_field_value (ps, PSTAT_PROC_INFO); ++ if (! err) ++ { ++ new->ppid = ps->proc_info->ppid; ++ new->pgid = ps->proc_info->pgrp; ++ new->sid = ps->proc_info->session; ++ new->tty_pgrp = ps->proc_info->pgrp; ++ } ++ else ++ { ++ new->ppid = 0; ++ new->pgid = 0; ++ new->sid = 0; ++ new->tty_pgrp = 0; ++ } ++ ++ err = set_field_value (ps, PSTAT_STATE); ++ if (! err) ++ new->flags = ps->state; ++ else ++ new->flags = 0; ++ ++ err = set_field_value (ps, PSTAT_TASK_EVENTS); ++ if (! err) ++ { ++ new->minflt = ps->task_events_info->faults; ++ new->majflt = ps->task_events_info->pageins; ++ } ++ else ++ { ++ new->minflt = 0; ++ new->majflt = 0; ++ } ++ ++ /* This seems to be a bit inconsistent with setting of other ++ fields in this code. There are two reasons for this. ++ 1. The actual information required is not made available ++ by libps which should be directly obtained from MACH. ++ 2. The same code which is required to get the information ++ have to be reused in procfs_nonpid_files.c */ ++ err = get_live_threads_time (ps, &utime, &stime); ++ if (! err) ++ { ++ new->utime = utime; ++ new->stime = stime; ++ } ++ else ++ { ++ new->utime = 0; ++ new->stime = 0; ++ } ++ ++ err = set_field_value (ps, PSTAT_TASK_BASIC); ++ if (! err) ++ { ++ new->cutime = adjust_jiffy_time ( ++ ps->task_basic_info->user_time); ++ new->cstime = adjust_jiffy_time ( ++ ps->task_basic_info->system_time); ++ ++ new->priority = ps->task_basic_info->base_priority; ++ new->starttime = adjust_jiffy_time ( ++ ps->task_basic_info->creation_time); ++ ++ new->vsize = ps->task_basic_info->virtual_size; ++ new->rss = ps->task_basic_info->resident_size; ++ } ++ else ++ { ++ new->cutime = 0; ++ new->cstime = 0; ++ new->priority = 0; ++ new->starttime = 0; ++ new->vsize = 0; ++ new->rss = 0; ++ } ++ ++ new->nice = getpriority (0, pid); ++ ++ err = set_field_value (ps, PSTAT_NUM_THREADS); ++ if (! err) ++ new->num_threads = ps->num_threads; ++ else ++ new->num_threads = 0; ++ ++ /* Not Supported in Linux 2.6 or later. */ ++ new->tty_nr = 0; ++ new->itrealvalue = 0; ++ new->nswap = 0; ++ new->cnswap = 0; ++ ++ /* Temporarily set to 0 until correct ++ values are found .*/ ++ new->cminflt = 0; ++ new->cmajflt = 0; ++ new->rlim = 0; ++ new->startcode = 0; ++ new->endcode = 0; ++ new->startstack = 0; ++ new->kstkesp = 0; ++ new->kstkeip = 0; ++ new->signal = 0; ++ new->blocked = 0; ++ new->sigignore = 0; ++ new->sigcatch = 0; ++ new->wchan = 0; ++ new->exit_signal = 0; ++ new->processor = 0; ++ new->rt_priority = 0; ++ new->policy = 0; ++ new->delayacct_blkio_ticks = 0; ++ ++ *procfs_stat = new; ++ _proc_stat_free (ps); ++ ++ return err; ++} ++ ++/* Reads required process information from stat file ++ within the directory represented by pid. Return ++ the data in DATA and actual length to be written ++ in LEN. */ ++error_t ++procfs_read_stat_file (struct procfs_dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ error_t err; ++ char *stat_data; ++ struct procfs_stat *procfs_stat; ++ pid_t pid = atoi (dir_entry->dir->node->nn->dir_entry->name); ++ ++ err = get_stat_data (pid, &procfs_stat); ++ ++ if (asprintf (&stat_data, "%d (%s) %s %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu \n", ++ procfs_stat->pid, procfs_stat->comm, ++ procfs_stat->state, procfs_stat->ppid, ++ procfs_stat->pgid, procfs_stat->sid, ++ procfs_stat->tty_nr, procfs_stat->tty_pgrp, ++ procfs_stat->flags, procfs_stat->minflt, ++ procfs_stat->cminflt, procfs_stat->majflt, ++ procfs_stat->cmajflt, procfs_stat->utime, ++ procfs_stat->stime, procfs_stat->cutime, ++ procfs_stat->cstime, procfs_stat->priority, ++ procfs_stat->nice, procfs_stat->num_threads, ++ procfs_stat->itrealvalue, procfs_stat->starttime, ++ procfs_stat->vsize, BYTES_TO_PAGES(procfs_stat->rss), ++ procfs_stat->rlim, procfs_stat->startcode, ++ procfs_stat->endcode, procfs_stat->startstack, ++ procfs_stat->kstkesp, procfs_stat->kstkeip, ++ procfs_stat->signal, procfs_stat->blocked, ++ procfs_stat->sigignore, procfs_stat->sigcatch, ++ procfs_stat->wchan, procfs_stat->nswap, ++ procfs_stat->cnswap, procfs_stat->exit_signal, ++ procfs_stat->processor, procfs_stat->rt_priority, ++ procfs_stat->policy, ++ procfs_stat->delayacct_blkio_ticks) == -1) ++ return errno; ++ ++ ++ memcpy (data, stat_data, strlen(stat_data)); ++ *len = strlen (data); ++ ++ free (stat_data); ++ free (procfs_stat); ++ ++ return err; ++} ++ ++/* Reads required process's command line information ++ from cmline file within the directory represented ++ by pid. Return the data in DATA and actual length ++ to be written in LEN. */ ++error_t ++procfs_read_cmdline_file (struct procfs_dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *cmdline_data; ++ error_t err; ++ struct proc_stat *ps; ++ pid_t pid = atoi (dir_entry->dir->node->nn->dir_entry->name); ++ err = _proc_stat_create (pid, ps_context, &ps); ++ ++ err = set_field_value (ps, PSTAT_ARGS); ++ ++ if (! err) ++ if (asprintf (&cmdline_data, "%s \n", ps->args) == -1) ++ return errno; ++ ++ memcpy (data, cmdline_data, strlen(cmdline_data)); ++ *len = strlen (data); ++ ++ _proc_stat_free (ps); ++ free (cmdline_data); ++ return err; ++} ++ ++/* Reads required process's information that is represented by ++ stat and statm in a human readable format from status file ++ within the directory represented by pid. Return the data ++ in DATA and actual length to be written in LEN. */ ++error_t ++procfs_read_status_file (struct procfs_dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *status_data; ++ error_t err; ++ struct proc_stat *ps; ++ struct procfs_stat *procfs_stat; ++ ++ pid_t pid = atoi (dir_entry->dir->node->nn->dir_entry->name); ++ err = _proc_stat_create (pid, ps_context, &ps); ++ ++ err = get_stat_data (pid, &procfs_stat); ++ ++ if (! err) ++ if (asprintf (&status_data, "Name:\t%s\nState:\t%s\nTgid:\t%d\nPid:\t%d\n", procfs_stat->comm, procfs_stat->state, procfs_stat->pid, procfs_stat->pid) == -1) ++ return errno; ++ ++ memcpy (data, status_data, strlen(status_data)); ++ *len = strlen (data); ++ ++ _proc_stat_free (ps); ++ ++ free (status_data); ++ free (procfs_stat); ++ ++ return err; ++} ++ ++/* Reads required process information from statm file ++ within the directory represented by pid. Return ++ the data in DATA and actual length to be written ++ in LEN. */ ++error_t ++procfs_read_statm_file (struct procfs_dir_entry *dir_entry, ++ off_t offset, size_t *len, void *data) ++{ ++ char *statm_data; ++ error_t err; ++ struct proc_stat *ps; ++ struct procfs_stat *procfs_stat; ++ ++ pid_t pid = atoi (dir_entry->dir->node->nn->dir_entry->name); ++ err = _proc_stat_create (pid, ps_context, &ps); ++ ++ err = get_stat_data (pid, &procfs_stat); ++ ++ if (! err) ++ if (asprintf (&statm_data, "%lu %ld %d %d %d %d %d\n", ++ BYTES_TO_PAGES(procfs_stat->vsize), ++ BYTES_TO_PAGES(procfs_stat->rss), ++ 0, 0, 0, 0, 0) == -1) ++ return errno; ++ ++ memcpy (data, statm_data, strlen(statm_data)); ++ *len = strlen (data); ++ ++ _proc_stat_free (ps); ++ ++ free (statm_data); ++ free (procfs_stat); ++ ++ return err; ++} ++ ++/* Reads required process information from each of files ++ within directory represented by pid, for files specified ++ by NODE. Return the data in DATA and actual length of ++ data in LEN. */ ++error_t ++procfs_read_files_contents (struct node *node, ++ off_t offset, size_t *len, void *data) ++{ ++ error_t err; ++ ++ if (! strcmp (node->nn->dir_entry->name, "stat")) ++ if (! strcmp (node->nn->dir_entry->dir->fs_path, "")) ++ err = procfs_read_nonpid_stat (node->nn->dir_entry, ++ offset, len, data); ++ else ++ err = procfs_read_stat_file (node->nn->dir_entry, ++ offset, len, data); ++ ++ if (! strcmp (node->nn->dir_entry->name, "cmdline")) ++ err = procfs_read_cmdline_file (node->nn->dir_entry, ++ offset, len, data); ++ ++ if (! strcmp (node->nn->dir_entry->name, "status")) ++ err = procfs_read_status_file (node->nn->dir_entry, ++ offset, len, data); ++ ++ if (! strcmp (node->nn->dir_entry->name, "statm")) ++ err = procfs_read_statm_file (node->nn->dir_entry, ++ offset, len, data); ++ ++ if (! strcmp (node->nn->dir_entry->name, "meminfo")) ++ if (! strcmp (node->nn->dir_entry->dir->fs_path, "")) ++ err = procfs_read_nonpid_meminfo (node->nn->dir_entry, ++ offset, len, data); ++ else ++ err = ENOENT; ++ ++ if (! strcmp (node->nn->dir_entry->name, "loadavg")) ++ if (! strcmp (node->nn->dir_entry->dir->fs_path, "")) ++ err = procfs_read_nonpid_loadavg (node->nn->dir_entry, ++ offset, len, data); ++ else ++ err = ENOENT; ++ ++ if (! strcmp (node->nn->dir_entry->name, "uptime")) ++ if (! strcmp (node->nn->dir_entry->dir->fs_path, "")) ++ err = procfs_read_nonpid_uptime (node->nn->dir_entry, ++ offset, len, data); ++ else ++ err = ENOENT; ++ ++ if (! strcmp (node->nn->dir_entry->name, "version")) ++ if (! strcmp (node->nn->dir_entry->dir->fs_path, "")) ++ err = procfs_read_nonpid_version (node->nn->dir_entry, ++ offset, len, data); ++ else ++ err = ENOENT; ++ ++ return err; ++} +--- a/Makefile ++++ b/Makefile +@@ -41,7 +41,7 @@ prog-subdirs = auth proc exec init term + login daemons nfsd boot console \ + hostmux usermux ftpfs trans \ + console-client utils sutils ufs-fsck ufs-utils \ +- benchmarks fstests ++ benchmarks fstests procfs + + # Other directories + other-subdirs = hurd doc config release include diff --git a/debian/patches/proxy-defpager.diff b/debian/patches/proxy-defpager.diff new file mode 100644 index 00000000..0ba12dee --- /dev/null +++ b/debian/patches/proxy-defpager.diff @@ -0,0 +1,59 @@ +https://savannah.gnu.org/bugs/?26751 + +2009-06-07 Zheng Da <zhengda1936@gmail.com> + + * Makefile: Use customized default_pager.defs. + + * proxy-defpager.c: Include customized default_pager header. + +--- + Makefile | 7 +++++-- + proxy-defpager.c | 5 +++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff -u -a -r1.40 -r1.40.10.1 +--- a/trans/Makefile 6 Jun 2007 16:08:56 -0000 1.40 ++++ b/trans/Makefile 7 Jun 2009 03:51:49 -0000 1.40.10.1 +@@ -26,13 +26,16 @@ + fakeroot.c proxy-defpager.c + OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \ + crashServer.o crash_replyUser.o msgServer.o \ +- default_pagerServer.o default_pagerUser.o \ ++ ourdefault_pagerServer.o ourdefault_pagerUser.o \ + device_replyServer.o elfcore.o + HURDLIBS = threads ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc + password-LDLIBS = $(LIBCRYPT) + + include ../Makeconf + ++ourdefault_pager.defs: default_pager.defs ++ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/MACH_MSG_TYPE_MAKE_SEND;/s/MAKE/COPY/' | sed -e '/subsystem/iserverprefix S_;' > $@ ++ + vpath elfcore.c $(top_srcdir)/exec + + symlink: fsysServer.o +@@ -40,7 +43,7 @@ + crash: crashServer.o crash_replyUser.o msgServer.o elfcore.o + password: passwordServer.o + streamio: device_replyServer.o +-proxy-defpager: default_pagerServer.o default_pagerUser.o ++proxy-defpager: ourdefault_pagerServer.o ourdefault_pagerUser.o + + proxy-defpager crash password streamio: ../libthreads/libthreads.a ../libports/libports.a ../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a + fifo new-fifo: ../libpipe/libpipe.a +diff -u -a -r1.5 -r1.5.10.1 +--- a/trans/proxy-defpager.c 6 Jun 2007 16:08:56 -0000 1.5 ++++ b/trans/proxy-defpager.c 7 Jun 2009 03:51:49 -0000 1.5.10.1 +@@ -23,9 +23,10 @@ + #include <error.h> + #include <version.h> + #include <hurd/paths.h> ++#include <string.h> + +-#include "default_pager_S.h" +-#include "default_pager_U.h" ++#include "ourdefault_pager_S.h" ++#include "ourdefault_pager_U.h" + + static mach_port_t real_defpager, dev_master; + diff --git a/debian/patches/rc.patch b/debian/patches/rc.patch new file mode 100644 index 00000000..228bb349 --- /dev/null +++ b/debian/patches/rc.patch @@ -0,0 +1,78 @@ +More debianish rc scripts +--- + daemons/rc.sh | 43 ++++++++++++++++++++++++++++++++----------- + 1 file changed, 32 insertions(+), 11 deletions(-) + +--- a/daemons/rc.sh ++++ b/daemons/rc.sh +@@ -19,14 +19,17 @@ then + echo Automatic boot in progress... + date + +- /sbin/fsck --preen --writable ++ fsysopts / --update --readonly ++ /sbin/fsck -p -A + + case $? in + # Successful completion + 0) ++ fsysopts / --update --writable + ;; + # Filesystem modified (but ok now) + 1 | 2) ++ fsysopts / --update --writable + ;; + # Fsck couldn't fix it. + 4 | 8) +@@ -85,7 +88,15 @@ if test -d /tmp; then + + fi + if test -d /var/run; then +- (cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; }) ++ (cd /var/run && { ++ find . ! -type d ! -name utmp ! -name innd.pid \ ++ -exec rm -f -- {} \; ++ cp /dev/null utmp ++ if grep -q ^utmp: /etc/group ++ then ++ chmod 664 utmp ++ chgrp utmp utmp ++ fi; }) + fi + echo done + +@@ -104,15 +115,25 @@ touch /var/run/mtab + + chmod 664 /etc/motd + +-echo -n starting daemons: ++( ++ trap ":" INT QUIT TSTP + +-/sbin/syslogd && echo -n ' syslogd' +-/sbin/inetd && echo -n ' inetd' +- +-if test -x /sbin/sendmail -a -r /etc/sendmail.cf; then +- /sbin/sendmail -bd -q30m && echo -n ' sendmail' +-fi +- +-echo . ++ if [ -d /etc/rc.boot ] ++ then ++ for i in /etc/rc.boot/S* ++ do ++ [ ! -f $i ] && continue ++ $i start ++ done ++ fi ++ if [ -d /etc/rc2.d ] ++ then ++ for i in /etc/rc2.d/S* ++ do ++ [ ! -f $i ] && continue ++ $i start ++ done ++ fi ++) + + date diff --git a/debian/patches/runsystem_setup_pflocal.patch b/debian/patches/runsystem_setup_pflocal.patch new file mode 100644 index 00000000..cd5a79eb --- /dev/null +++ b/debian/patches/runsystem_setup_pflocal.patch @@ -0,0 +1,21 @@ +Automatically setup local sockets if not already done so. Needed early for shell +pipelines. +--- + daemons/runsystem.sh | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/daemons/runsystem.sh ++++ b/daemons/runsystem.sh +@@ -53,6 +53,12 @@ function singleuser () + } + + ++# See whether pflocal is setup already, and do so if not (install case) ++ ++if ! test -e /servers/socket/1 && which settrans >/dev/null ; then ++ settrans -c /servers/socket/1 /hurd/pflocal ++fi ++ + # We expect to be started by console-run, which gives us no arguments and + # puts FALLBACK_CONSOLE=file-name in the environment if our console is + # other than a normal /dev/console. diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 00000000..02c62bdc --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,36 @@ +console_utf-8.patch +diskfs_no_inherit_dir_group.patch +ext2fs_large_stores.patch +hurd_console_startup.patch +init_try_runsystem.gnu.patch +install-msgids.diff +libpager_update_seqno.patch +libpthread_mutex_owner.patch +libpthread_stubs.patch +libpthread_tls.patch +makedev.diff +pfinet_dhcp.patch +pflocal.patch +procfs.patch +rc.patch +runsystem_setup_pflocal.patch +startup-usr-support.patch +tmp_exec_startup.patch +ttys.patch +uptime_w_path_fix.patch +stat_round.patch +dir_acces_fix.patch +libports_stability.patch +libpthread_fix.patch +libpthread_setcancel.patch +extern_inline_fix.patch +exec_fix.patch +libpthread_recursive_mutex_initializer.patch +pfinet-gcc-4.3-fix.patch +MAKEDEV.patch +libdiskfs-rename.patch +libpthread_cancel_init.patch +libpthread_kill_0.patch +console_current_vcs.patch +tmpfs.patch +proxy-defpager.diff diff --git a/debian/patches/startup-usr-support.patch b/debian/patches/startup-usr-support.patch new file mode 100644 index 00000000..9281ec29 --- /dev/null +++ b/debian/patches/startup-usr-support.patch @@ -0,0 +1,27 @@ +Debian GNU/Hurd has a real /usr +--- + daemons/rc.sh | 2 +- + daemons/runsystem.sh | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/daemons/rc.sh ++++ b/daemons/rc.sh +@@ -1,6 +1,6 @@ + #!/bin/bash + +-PATH=/bin:/sbin ++PATH=/bin:/sbin:/usr/bin:/usr/sbin + + # Start the default pager. It will bail if there is already one running. + /hurd/mach-defpager +--- a/daemons/runsystem.sh ++++ b/daemons/runsystem.sh +@@ -11,7 +11,7 @@ + ### Where to find programs, etc. + ### + +-PATH=/bin:/sbin ++PATH=/bin:/sbin:/usr/bin:/usr/sbin + export PATH + + # If we lose badly, try to exec each of these in turn. diff --git a/debian/patches/stat_round.patch b/debian/patches/stat_round.patch new file mode 100644 index 00000000..38454ba6 --- /dev/null +++ b/debian/patches/stat_round.patch @@ -0,0 +1,52 @@ +--- + libdiskfs/file-utimes.c | 4 ++-- + libdiskfs/node-times.c | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/libdiskfs/file-utimes.c ++++ b/libdiskfs/file-utimes.c +@@ -33,7 +33,7 @@ diskfs_S_file_utimes (struct protid *cre + else + { + np->dn_stat.st_atim.tv_sec = atime.seconds; +- np->dn_stat.st_atim.tv_nsec = atime.microseconds * 1000; ++ np->dn_stat.st_atim.tv_nsec = 0; + np->dn_set_atime = 0; + } + +@@ -42,7 +42,7 @@ diskfs_S_file_utimes (struct protid *cre + else + { + np->dn_stat.st_mtim.tv_sec = mtime.seconds; +- np->dn_stat.st_mtim.tv_nsec = mtime.microseconds * 1000; ++ np->dn_stat.st_mtim.tv_nsec = 0; + np->dn_set_mtime = 0; + } + +--- a/libdiskfs/node-times.c ++++ b/libdiskfs/node-times.c +@@ -53,21 +53,21 @@ diskfs_set_node_times (struct node *np) + if (np->dn_set_mtime) + { + np->dn_stat.st_mtim.tv_sec = t.tv_sec; +- np->dn_stat.st_mtim.tv_nsec = t.tv_usec * 1000; ++ np->dn_stat.st_mtim.tv_nsec = 0; + np->dn_stat_dirty = 1; + np->dn_set_mtime = 0; + } + if (np->dn_set_atime) + { + np->dn_stat.st_atim.tv_sec = t.tv_sec; +- np->dn_stat.st_atim.tv_nsec = t.tv_usec * 1000; ++ np->dn_stat.st_atim.tv_nsec = 0; + np->dn_stat_dirty = 1; + np->dn_set_atime = 0; + } + if (np->dn_set_ctime) + { + np->dn_stat.st_ctim.tv_sec = t.tv_sec; +- np->dn_stat.st_ctim.tv_nsec = t.tv_usec * 1000; ++ np->dn_stat.st_ctim.tv_nsec = 0; + np->dn_stat_dirty = 1; + np->dn_set_ctime = 0; + } diff --git a/debian/patches/tmp_exec_startup.patch b/debian/patches/tmp_exec_startup.patch new file mode 100644 index 00000000..0c77b16d --- /dev/null +++ b/debian/patches/tmp_exec_startup.patch @@ -0,0 +1,52 @@ +Also try /tmp/exec as it's used for installation. +--- + libdiskfs/boot-start.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +--- a/libdiskfs/boot-start.c ++++ b/libdiskfs/boot-start.c +@@ -126,8 +126,13 @@ diskfs_start_bootstrap () + assert (_hurd_ports); + assert (_hurd_ports[INIT_PORT_CRDIR].port != MACH_PORT_NULL); + diskfs_exec = file_name_lookup (_SERVERS_EXEC, 0, 0); +- if (diskfs_exec == MACH_PORT_NULL) +- error (1, errno, "%s", _SERVERS_EXEC); ++ if (diskfs_exec == MACH_PORT_NULL) ++ { ++ /* Debian specifc work-around for install bootstrapping. */ ++ diskfs_exec = file_name_lookup ("/tmp/exec", 0, 0); ++ if (diskfs_exec == MACH_PORT_NULL) ++ error (1, errno, "%s", _SERVERS_EXEC); ++ } + else + { + #ifndef NDEBUG +@@ -177,8 +182,15 @@ diskfs_start_bootstrap () + &retry, pathbuf, &execnode); + if (err) + { +- error (0, err, "cannot set translator on %s", _SERVERS_EXEC); +- mach_port_deallocate (mach_task_self (), diskfs_exec_ctl); ++ /* If /servers/exec is not available (which is the case during ++ installation, try /tmp/exec as well. */ ++ err = dir_lookup (root_pt, "/tmp/exec", O_NOTRANS, 0, ++ &retry, pathbuf, &execnode); ++ if (err) ++ { ++ error (0, err, "cannot set translator on %s", _SERVERS_EXEC); ++ mach_port_deallocate (mach_task_self (), diskfs_exec_ctl); ++ } + } + else + { +@@ -393,6 +405,10 @@ diskfs_execboot_fsys_startup (mach_port_ + + err = dir_lookup (rootport, _SERVERS_EXEC, flags|O_NOTRANS, 0, + &retry, pathbuf, real); ++ if (err) ++ /* Try /tmp/exec as well, in case we're installing. */ ++ err = dir_lookup (rootport, "/tmp/exec", flags|O_NOTRANS|O_CREAT, 0, ++ &retry, pathbuf, real); + assert_perror (err); + assert (retry == FS_RETRY_NORMAL); + assert (pathbuf[0] == '\0'); diff --git a/debian/patches/tmpfs.patch b/debian/patches/tmpfs.patch new file mode 100644 index 00000000..63e4de37 --- /dev/null +++ b/debian/patches/tmpfs.patch @@ -0,0 +1,21 @@ +commit 97c5690abeaa88767acf2ffbb55552e8278052c8 +Author: Samuel Thibault <samuel.thibault@ens-lyon.org> +Date: Mon Jan 11 03:34:50 2010 +0100 + + Fix tmpfs assertion + + * tmpfs/tmpfs.h (tmpfs_dirent): Add padding field to push the + name field after its position in struct dirent. + +diff --git a/tmpfs/tmpfs.h b/tmpfs/tmpfs.h +index 3032ce3..a0e1f7a 100644 +--- a/tmpfs/tmpfs.h ++++ b/tmpfs/tmpfs.h +@@ -64,6 +64,7 @@ struct tmpfs_dirent + { + struct tmpfs_dirent *next; + struct disknode *dn; ++ uint32_t pad; + uint8_t namelen; + char name[0]; + }; diff --git a/debian/patches/ttys.patch b/debian/patches/ttys.patch new file mode 100644 index 00000000..eed10854 --- /dev/null +++ b/debian/patches/ttys.patch @@ -0,0 +1,18 @@ +Add Marcus' console ttys. +--- + config/ttys | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/config/ttys ++++ b/config/ttys +@@ -5,4 +5,10 @@ + # name program type status comments + + console "/libexec/getty 9600" mach-color on secure trusted console ++tty1 "/libexec/getty 38400" hurd on secure trusted console ++tty2 "/libexec/getty 38400" hurd on secure trusted console ++tty3 "/libexec/getty 38400" hurd on secure trusted console ++tty4 "/libexec/getty 38400" hurd on secure trusted console ++tty5 "/libexec/getty 38400" hurd on secure trusted console ++tty6 "/libexec/getty 38400" hurd on secure trusted console + #com0 "/libexec/getty 9600" dialup on secure diff --git a/debian/patches/uptime_w_path_fix.patch b/debian/patches/uptime_w_path_fix.patch new file mode 100644 index 00000000..3d5f1c39 --- /dev/null +++ b/debian/patches/uptime_w_path_fix.patch @@ -0,0 +1,16 @@ +Debian has a real /usr +--- + utils/uptime.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/utils/uptime.sh ++++ b/utils/uptime.sh +@@ -25,7 +25,7 @@ + USAGE="Usage: $0 [OPTION...]" + DOC="Show system uptime, number of users, and load" + +-W=${W-/bin/w} ++W=${W-/usr/bin/w} + + while :; do + case "$1" in diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..8dcb55e8 --- /dev/null +++ b/debian/rules @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- +# Copyright © 2003 Jeff Bailey <jbailey@debian.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, 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., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +DEB_BUILDDIR = $(DEB_SRCDIR)/build + +CC=gcc-4.3 + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk + +DEB_CONFIGURE_LIBEXECDIR ="\$${prefix}/libexec" +DEB_CONFIGURE_USER_FLAGS := --disable-profile --enable-static-progs='ext2fs,ufs,iso9660fs' +DEB_MAKE_INSTALL_TARGET = install prefix=$(DEB_DESTDIR) sysconfdir=$(DEB_DESTDIR)/etc localstatedir=$(DEB_DESTDIR)/var +DEB_DH_STRIP_ARGS := --dbg-package=hurd-dbg +DEB_INSTALL_CHANGELOGS_ALL := $(CURDIR)/debian/ChangeLog +DEB_DH_MAKESHLIBS_ARGS_hurd := --add-udeb="hurd-udeb" + +build/hurd:: + cd $(DEB_BUILDDIR)/doc && texi2html -split chapter ../../doc/hurd.texi + + # assemble all ChangeLogs to one big file + cd $(DEB_SRCDIR); for i in `find hurd/ -name "ChangeLog"`; do echo $$i:; cat $$i; echo; done > $(CURDIR)/debian/ChangeLog + +install/hurd:: + # runsystem is managed by update-alternatives + mv debian/tmp/libexec/runsystem debian/tmp/libexec/runsystem.gnu + + # move away fakeroot, ps, uptime, vmstat and w to not conflict with the + # ones from other packages + mkdir -p debian/tmp/usr/bin + mv debian/tmp/bin/fakeroot debian/tmp/usr/bin/fakeroot-hurd + mv debian/tmp/bin/ps debian/tmp/bin/ps-hurd + mv debian/tmp/bin/uptime debian/tmp/usr/bin/uptime-hurd + mv debian/tmp/bin/vmstat debian/tmp/usr/bin/vmstat-hurd + mv debian/tmp/bin/w debian/tmp/usr/bin/w-hurd + + install -m664 debian/hurd-console.default debian/hurd/etc/default/hurd-console + + install -m664 $(DEB_SRCDIR)/console/motd.UTF8 debian/hurd/etc/ + install -m664 $(DEB_SRCDIR)/release/servers.boot debian/hurd/boot/ + +install/hurd-dev:: + install -m644 debian/local/soundcard.h debian/tmp/include/sys + +SUID_PROGRAMS = /bin/ids /bin/login /bin/ps-hurd /usr/bin/w-hurd + +binary-predeb/hurd:: + chmod u+s $(patsubst %, $(CURDIR)/debian/$(cdbs_curpkg)%, $(SUID_PROGRAMS)) +binary-predeb/hurd-dev:: + rm -f $(CURDIR)/debian/hurd-dev/lib/*_pic.a + diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) |
